Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Script to streamline nftables editing
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Networking & Security
View previous topic :: View next topic  
Author Message
jesnow
l33t
l33t


Joined: 26 Apr 2006
Posts: 895

PostPosted: Tue Feb 04, 2025 9:10 pm    Post subject: Script to streamline nftables editing Reply with quote

Hi folks:

I have to apologize in advance that this is too long. I'm not a pro at this and I'm sure it can be done better. Certain aspects of nftables trip me up every time -- I can't be alone in this.

One of these is the persistence behavior of nftables. Iptables did this too: It expects you to edit the running ruleset, adding and deleting rules until everything routes or is blocked the way it's supposed to. And then you can just walk away because the serializaiton is built in. When you restart the system, it saves itself off to /var/lib/nftables.save and brings it back when the system starts again. Great! And if you want there is a convenient /etc/nftables.conf you can tinker with if you wish. This is great, but not for ordinary users (ie me).

Why? Becuase every other daemon in the world reads its config file from /etc on start, builds its environment, and runs. So when you give "/etc/init.d/most-daemons restart", that prompts it to reload its configuration you just edited from /etc. But that's not what nftables does or iptables did. And unless you flush and reload by hand, without help from the openrc init system (who knows what systemd does), you can't have that behavior. There's all kinds of verbs in /etc/init.d/nftables, but none of them reloads the ruleset from /etc. Instead, it puts the ruleset back to what it was before from /var and ignores your puny config file.

So you may say I'm an idiot, but I like my daemons to load their config file from /etc. And there is a way to make it do that, if you change the save file location to that in /etc/conf.d/nftables. But the problem with that is, now the nftables init script *overwrites* your ruleset, and does it with the obfuscatory "-n" option. Yes, you can change that too, but at the very least now all your comments are gone that tell you what all these rules do.

And honestly, there's nothing wrong with the original "standard" behavior until you want to go and monkey with the firewall. Then you might want to edit /etc/nftables.conf and have nftables rebuild itself, diff the new ruleset with the old ruleset and give you the choice of going back and fixing your mistakes before you wreck the running ruleset. Oh, yes, and log everything.

So I wrote a script that does that: It patches the init script to only use literal mode, then it flushes and reloads the ruleset from /etc/nftables.conf, then it compares the new ruleset with the one saved off in /var/lib, and prompts you to accept or reject the changes. I didn't want to edit the init script, since that was sure to be overwritten someday. But if you guys like it maybe an option could be added to the init script to do it this way.

Code:

merckx /home/jesnow # cat /usr/local/bin/nftables-reload
#!/bin/sh

# Source OpenRC's nftables config
. /etc/conf.d/nftables

RULESET_TMP=$(mktemp)
LOG_TAG="nftables-reload"
INIT_SCRIPT="/etc/init.d/nftables"
SEARCH="_nftables store"
REPLACE="nft list ruleset >"

echo "Check and patch OpenRC's nftables init script if needed"
if grep -q "$SEARCH" "$INIT_SCRIPT"; then
    echo "Patching OpenRC's nftables init script..."
    sed -i "s|$SEARCH|$REPLACE|g" "$INIT_SCRIPT"
    echo "Patched OpenRC's nftables init script to use preferred save method."
    logger -t nftables-reload "Patched OpenRC nftables init script to use 'nft list ruleset' for saving."
fi

echo "Flushing and reloading nftables from /etc/nftables.conf..."
nft flush ruleset
nft -f /etc/nftables.conf

echo "Restarting Fail2Ban to restore bans..."
rc-service fail2ban restart
sleep 1

echo "Saving the current running ruleset to a temporary file..."
nft list ruleset > "$RULESET_TMP"

echo "Comparing the current running ruleset with the saved private ruleset..."
if [ -f "$NFTABLES_SAVE" ] && ! diff -u "$NFTABLES_SAVE" "$RULESET_TMP"; then
    echo "Differences detected between configured ruleset and previous saved ruleset."
    echo "Proceed with saving the new ruleset? (Y/n)"
    read -r CONFIRMATION
    if [ -z "$CONFIRMATION" ] || [ "$CONFIRMATION" = "Y" ] || [ "$CONFIRMATION" = "y" ]; then
        echo "Saving new ruleset..."
        rm -f $NFTABLES_SAVE
        # /etc/init.d/nftables save
        nft list ruleset > $NFTABLES_SAVE
        /etc/init.d/nftables reload
        logger -t "$LOG_TAG" "Updated nftables ruleset and saved changes"
    else
        echo "Reverting to the previous saved ruleset..."
        /etc/init.d/nftables reload
        logger -t "$LOG_TAG" "Reverted to previous nftables ruleset"
    fi
else
    echo "No differences detected. No changes needed."
fi

echo "Cleaning up temporary files..."
rm -f "$RULESET_TMP"

echo "Done."


Now when I want to check on my running ruleset I can give:

Code:


merckx /home/jesnow # nftables-reload
Check and patch OpenRC's nftables init script if needed
Flushing and reloading nftables from /etc/nftables.conf...
Restarting Fail2Ban to restore bans...
OK: configuration test is successful
 * Stopping fail2ban ...                                                                                                           [ ok ]
 * Starting fail2ban ...
Server ready                                                                                                                       [ ok ]
Saving the current running ruleset to a temporary file...
Comparing the current running ruleset with the saved private ruleset...
--- /var/lib/nftables/rules-save        2025-02-04 14:02:56.568921934 -0600
+++ /tmp/tmp.KC8cQ2mO8L 2025-02-04 14:49:58.316547227 -0600
@@ -8,6 +8,7 @@
                ip saddr 185.147.124.182 drop
                ip saddr 92.255.85.107 drop
                ip saddr 185.147.124.0/24 drop
+               ip saddr 185.42.12.0/24 drop
                iif "wg0" accept
                iif "enp3s0" accept
                ip protocol icmp accept
@@ -19,3 +20,15 @@
                drop
        }
 }
+table inet f2b-table {
+       set addr-set-sshd-invalid-user {
+               type ipv4_addr
+               elements = { 92.255.85.253, 185.42.12.141,
+                            185.42.12.240, 185.147.124.49 }
+       }
+
+       chain f2b-chain {
+               type filter hook input priority filter - 1; policy accept;
+               tcp dport 22 ip saddr @addr-set-sshd-invalid-user reject with icmp port-unreachable
+       }
+}
Differences detected between configured ruleset and previous saved ruleset.
Proceed with saving the new ruleset? (Y/n)



Well lookee there, fail2ban has done banned a few more. Great! "Y".

Code:

Proceed with saving the new ruleset? (Y/n)

Saving new ruleset...
 * Checking rules ...                                                                                                              [ ok ]
 * Loading nftables state and starting firewall ...                                                                                [ ok ]
Cleaning up temporary files...
Done.
merckx /home/jesnow #


It saves the new ruleset in /var/lib, then reloads from that and cleans up.

If I don't like what it did, it reloads the old ruleset, but doesn't overwrite my /etc/nftables.conf so I can go back and figure out what went wrong.

NOW, the next time I run it:

Code:

merckx /home/jesnow # nftables-reload
Check and patch OpenRC's nftables init script if needed
Flushing and reloading nftables from /etc/nftables.conf...
Restarting Fail2Ban to restore bans...
OK: configuration test is successful
 * Stopping fail2ban ...                                                                                                           [ ok ]
 * Starting fail2ban ...
Server ready                                                                                                                       [ ok ]
Saving the current running ruleset to a temporary file...
Comparing the current running ruleset with the saved private ruleset...
No differences detected. No changes needed.
Cleaning up temporary files...
Done.


Nothing to see here, all done! I feel like this gives a workflow that's more like what we expect daemons to do (read your config from /etc/when I reload you!) while not changing too much the expected behavior the rest of the time. It also keeps etc for user data and /var for private data.

I hope somebody finds this a useful crutch for people who find the default nftables verbs in openrc counterintuitive.

Cheers,
jon.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Networking & Security All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum