Learning NFTables/FW4

hello.

brand new to NFT, hadn't even heard about it before last week when I started looking at updating to current OpenWRT. spent some time today putting the old FW3 custom rules I had into FW4 format. these seem to be working for me but I thought I would put it out there to see if there's a "better" way to skin this cat since it's all super-new to me.

also, how do I get these to load every firewall refresh now that the user config is gone? just throw it into /usr/share/nftables.d as-is?

sorry if these are stupid questions, I did search just didn't see anything super-relevant.

## dns stuff, need a set of local servers...
nft 'add set inet fw4 dns { type ipv4_addr; comment "local dns servers"; }'
nft 'add element inet fw4 dns { x.x.x.8, x.x.x.9 }'

# redirect dns and dns-over-tls...
nft 'insert rule inet fw4 dstnat_lan ip saddr != @dns tcp dport {53,853} counter redirect'
nft 'insert rule inet fw4 dstnat_lan ip saddr != @dns udp dport {53,853} counter redirect'

# block doh providers except to local dns servers...
nft 'add set inet fw4 doh { type ipv4_addr; comment "remote doh servers"; }'
nft 'flush set inet fw4 doh'
cat /root/doh.txt |sed -e 's/.*/{&}/' |xargs -n1 nft add element inet fw4 doh
nft 'add chain inet fw4 reject_doh'
nft 'add rule inet fw4 reject_doh ip protocol icmp accept'
nft 'add rule inet fw4 reject_doh ip saddr @dns accept'
nft 'add rule inet fw4 reject_doh counter log reject'
nft 'insert rule inet fw4 accept_to_wan ip daddr @doh jump reject_doh'

# reject outbound smtp
nft 'define smtp={ x.x.x.11 }; \
	insert rule inet fw4 accept_to_wan ip saddr != $smtp udp dport {25,465,587,2525} counter log reject; \
	insert rule inet fw4 accept_to_wan ip saddr != $smtp tcp dport {25,465,587,2525} counter log reject'

so I think I found an answer, appears to be working. put a symlink in /etc/hotplug.d/iface/99-firewall-custom pointing to the script and it appears to run the commands after restarting the interface.

lots of talk about how to handle this, looks like the method settled on was dropping files in /etc/nftables.d but this wouldn't work for my use-case since they would have to be static and I load a dynamic set.

You can use script includes:

config include
  option type script
  option path /etc/my-custom-firewall-script.sh

This will get executed on every ruleset reload.

Which pieces of your set are dynamic? The IP addresses? In this case you might want consider loading a static ruleset with (empty) named sets, then just populate those sets from a hotplug handler or similar suitable hook.

the list of DoH IPs is dynamic, but to be fair it only updates when I do a system update so not super frequent.

what would be the benefit of splitting the script up if I would just need to run a script on ifup anyways?

No real benefit if you just need to maintain a list of rarely updated ips. It would make sense if you have frequently changing lists, due to dynamic block lists or the like

rewritten to use a custom table instead of messing with fw4...

# setup table, chains...
nft 'delete table inet custom; add table inet custom'
nft 'add set inet custom doh { type ipv4_addr; comment "remote doh servers"; }'
nft 'add chain inet custom redirect_dns { type nat hook prerouting priority -1; }'
nft 'add chain inet custom check_outbound { type filter hook forward priority 100; }'
nft 'add chain inet custom reject_doh'

# define statements are only good for a single command so setup rules all at once...
nft 'define dns={ x.x.x.8, x.x.x.9 }; \
	define smtp={ x.x.x.11 }; \
	define wan={ eth0.2 }; \
	add rule inet custom redirect_dns iifname $wan return; \
	add rule inet custom redirect_dns ip saddr != $dns udp dport {53,853} counter redirect; \
	add rule inet custom redirect_dns ip saddr != $dns tcp dport {53,853} counter redirect; \
	add rule inet custom check_outbound oifname != $wan return; \
	add rule inet custom check_outbound ip daddr @doh jump reject_doh; \
	add rule inet custom check_outbound ip saddr != $smtp tcp dport {25,465,587,2525} counter log reject; \
	add rule inet custom check_outbound ip saddr != $smtp udp dport {25,465,587,2525} counter log reject; \
	add rule inet custom reject_doh ip saddr $dns counter accept; \
	add rule inet custom reject_doh ip protocol icmp counter accept; \
	add rule inet custom reject_doh counter log reject;'

# populating set, can be run outside ifup if warranted...
nft flush set inet custom doh
cat /root/doh.txt |sed '1!G;h;$!d' |sed -e 's/.*/{&}/' |xargs -n1 nft add element inet custom doh