Updated nftables

I've updated my notes on nftables, so it works of 19.07.
The main loading of rules hasn't changed. However when I updated to 19.07 I could see that I think all nftables modules are loaded. Also I could stop iptable NAT loading by removing /etc/modules.d/ipt-nat, so the modules are still there, and just not loaded, which is easier than remove them.

Though I asks if there were any comments, anything to change or make better. In particular removing /etc/modules.d/ipt-nat means that:

  • iptable_nat
  • xt_nat

Don't load. Its clear that ipt_MASQUERADE and iptable_nat should not be loaded, but I'm not sure about the xt_* modules. I need to look them up.

Any other thoughts let me know. I know I have to update how to let in ssh, to something safer than written. I do this when I come up with something better.


During a transitional period, testing nft, I found it more convenient (easier to reverse if something goes awry) to unload ipt rather than making the surgical step at that point of removing kernel modules.

This hover presented a challenge, least to me back then, as the ipt would not unload and thus thought to share the gained knowledge.
At first I thought the kernel modules would not unload due to interdependencies and with modprobe -r lacking in busybox it seemed neigh infeasible to discover the potential chain of module interdependencies and work out a suitable reverse unloading sequence.

The cause however is that with having FW3 stopped there is a data residue in the ipt chains and subsequent the kernel modules would not unload. Thus this worked for me then:

1 ) flush and clear the ipt chains (mind you want basic nft rules deployed already prior as not to loose acces to the node)

iptables -vF ; iptables -vX ; iptables -t nat -vF ; iptables -t nat -vX ; iptables -t mangle -vF ; iptables -t mangle -vX ; iptables -t raw -vF ; iptables -t raw -vX ; iptables -t security -vF ; iptables -t security -vX ; ip6tables -vF ; ip6tables -vX ; ip6tables -t nat -vF ; ip6tables -t nat -vX ; ip6tables -t mangle -vF ; ip6tables -t mangle -vX ; ip6tables -t raw -vF ; ip6tables -t raw -vX ; ip6tables -t security -vF ; ip6tables -t security -vX

2 ) unload ipt ipv4 modules

rmmod iptable_nat ; rmmod iptable_raw ; rmmod iptable_mangle ; rmmod iptable_secuity ; rmmod iptable_filter ; rmmod ip_tables ; rmmod ipt_MASQUERADE ; rmmod ipt_ECN ; rmmod ipt_REJECT ; rmmod ipt_rpfilter

3 ) unload ipt ipv6 modules

rmmod ip6table_nat ; rmmod ip6table_raw ; rmmod ip6table_mangle ; rmmod iptable_secuity ; rmmod ip6table_filter ; rmmod ip6_tables ; rmmod ip6t_REJECT ; rmmod ip6t_ah ; rmmod ip6t_eui64 ; rmmod ip6t_frag ; rmmod ip6t_hbh ; rmmod ip6t_ipv6header ; rmmod ip6t_mh ; rmmod ip6t_rt ; rmmod ip6t_rpfilter

It is rater unfortunate the OpenWrt does not provide userland, though not infallible,

  • iptables-translate
  • iptables-restore-translate

that could assist potentially interested adopters with the transition from ipt to nft if no other Linux (derivate) node is at hand.

[1] https://wiki.nftables.org/wiki-nftables/index.php/Moving_from_iptables_to_nftables

1 Like

Yes - you can only unload kernel modules when nothing is using them. becuase of how the network in the kernel is spread between many modules, its very hard to remove using rmmod. So the better way to do it is in the directory /etc/modules.d find the file that names the module you don't want loaded, then removing that file, and on the next boot the module won't be loaded, this is far esier than trying to remove already loaded modules.

For that purpose I shared my findings and how to get it done for the particular ipt modules, if someone would be interested to pursue that avenue as alternative.

Anyway, potential conflicts between ipt and nft would seem absent from the Master branch with kernel 4.19.x

For me, the nftable rules

flush ruleset 

table ip nat {
	chain prerouting {
		type nat hook prerouting priority filter; policy accept;

	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		meta oiftype ppp masquerade

That clear the tables, and then load the NAT elements of nf tables, gives me an error like IP table NAT is loaded. This is when the ip table nat kernel module is not loaded. This is on opewrt 19.07 which runs the 4.19 kernel. So this doesn't seem to tally with their being no conflicts.

So what is your hardware that shows the conflict as absent?

Been Master on mvebu target not that long ago but having moved on since then with everything ipt related uninstalled now anyway.

The fw3 flush command should clear out everything. An fw3 stop usually just purges its own fw3 specific rules.

1 Like

It may, have not tried it and now with FW3 removed I am not going to reinstall it and see whether it works.

Recommendations are citing not only to -F (flush) but also -X (delete) the ipt chains, least that is what I followed and which permitted for the ipt modules to be unloaded.

provided you use a proper randomly generated password, like a 10 character ascii password provided by keepass, I think letting the WAN accept ssh with on the order of 1/second per IP address is relatively safe. A rule like:

ct state new tcp dport ssh meter sshmeter {ip saddr . ip daddr limit rate 1/s burst 10 packets } accept

Assuming the default is drop, makes it basically impossible for people to effectively attack the ssh port. At 1/second trying 127^7 different passwords would take 17 million years, so even with a botnet of 1M routers to coordinate an attack an 8 character password would take on average 16 years to crack by brute force.

if someone is willing to put a 1M host botnet to work cracking your router, they probably will use a different tactic.

1 Like

Well although rate limiting is one way of lessing the problem, it isn't a solution to my mind, your log still gets filled with hack attempts.

Its worth though going into the source of the problem, in prerouting an external port is forwarded to and internal machine on port 22. Now the problem is when that packet leaves prerouting, and enters the main input/forward loop its going to port 22, so you have to let it through. Hence the push to open port 22, but then port 22 as well as the other port get let through.

Ideally what I'd do is when the packet is dnat in prerouting, that it is also marked, and that mark is what is allowed through. Then you don't need to open port 22.

A half way solution though is enabling port 22 in the forward rules, but not in the input rules. Then only forwarded packets are let through, and the only real place that the forward packets from the WAN originate from is the DNAT for ssh.

Anyway hassle for me, is things like this really should be done with testing. Whilst I used to previously log into my home network remotly alot, change in life means I don't do it any more. So not easy for me to test remotely.

But it still on my list of things to do, really just to tidy up the nftable page. I'd prefer it shows a very good example of routing, rather than an example with some holes in. Think this is part of the hassle of firewalls, configuring them to do exactly what you want, is exceptionally difficult in iptables, and far from simple in nftables.

Think to my mind thats why its good to get other involved in discussions on nftables, its only when people try it, they can see how it compares with iptables, and how to impliment things. Really its expsure to nftables, that will make people move to them ...

So solution something like:

table ip nat {
	chain prerouting {
		type nat hook prerouting priority 0; policy accept;
		tcp dport 12345 dnat to meta mark set 76

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
table inet filter {
	chain forward {
		type filter hook forward priority 0; policy drop;
		ct state { related, established } accept
		ct state invalid drop  
		iiftype != ppp accept
		meta mark 76 accept
		iiftype ppp drop


But this is totally untested - just a brain dump.

Adding init script (works for me)

#!/bin/sh /etc/rc.common

DESC="firewall service"

start_service() {
	# Return
	#  0 if start OK
	#  2 if start NOK

	if [ ! -r "$CONF" ] ; then
		return 2
		logger -st $NAME $DESC "Error: No such config file $CONF"

	procd_set_param command $BIN -f $CONF
	procd_append_param command || return 0
	procd_set_param file $CONF

stop_service() {
	$BIN flush ruleset
	logger -st $NAME $DESC "stopped and ruleset flushed"

boot() {

Hi! Your guide really helped me to get nftables up and running. I think this information could be interesting too for all people willing to switch to nftables completely. But I'm not sure, so I'm just leaving this comment here instead of editing the wiki.