Iptables vs nft

I'm not a firewall guy but I have a bunch of scripts I've used over the years that are iptables commands.
In 22.03.3, those aren't working anymore and it seems to be because the package is now called iptables-nft.

In fact, there are a bunch of packages that seem to be related.

iptables-nft - 1.8.7-7
kmod-nft-compat - 5.10.161-1
kmod-nft-core - 5.10.161-1
kmod-nft-fib - 5.10.161-1
kmod-nft-nat - 5.10.161-1
kmod-nft-offload - 5.10.161-1
libiptext-nft0 - 1.8.7-7
libnftnl11 - 1.2.1-2
nftables-json - 1.0.2-2.1
xtables-nft - 1.8.7-7

I can't seem to find enough information on how to convert my iptables commands so wondering if there is a way to continue using the old iptables instead of this new one.

1 Like

Thanks. I'll take a look at all this.

1 Like

AFAIK iptables-nft tables should be able to handle iptables syntax but you can also use the helper to translate to native nft, see: https://wiki.nftables.org/wiki-nftables/index.php/Moving_from_iptables_to_nftables

2 Likes

Yes, I was just reading that, about being able to use the same commands. Strange.

BTW, could I continue using iptables, not just the command but the old method?
What I mean is that when using my old router running 18.06.0, this works just fine but it's broken on the 22.03.3 router I'm working on.

It's confusing because everything but port forwarding works.

From a remote over the vpn, I cannot reach a blocked port on the router.
From a remote over the vpn, I can reach a port running on the router.
From a remote over the vpn, I cannot reach a port forwarded to another device on the LAN.

I've tried all kinds of variations and what I'm sharing is just yet another variation and cannot find a reason for this blocking. The port forwarding never works.

$ iptables -S
# Warning: iptables-legacy tables present, use iptables-legacy to see them
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A FORWARD -i br-lan -o tun+ -j ACCEPT
-A FORWARD -i tun+ -o br-lan -j ACCEPT

$ iptables -S -t nat
# Warning: iptables-legacy tables present, use iptables-legacy to see them
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A PREROUTING -i tun+ -p tcp -m tcp --dport 81 -j DNAT --to-destination 192.168.1.99:80
-A POSTROUTING -o br-lan -j MASQUERADE
-A POSTROUTING -o tun+ -j MASQUERADE
From the remote vpn;

# curl 172.16.1.15:22
SSH-2.0-dropbear
***this works***

# curl 172.16.1.15:81
curl: (7) Failed connect to 172.16.1.15:81; Connection refused

On the openwrt router;

Sun May 21 19:04:10 2023 kern.info kernel: [10025.466434] device tun0 entered promiscuous mode
Sun May 21 19:04:24 2023 authpriv.info dropbear[26392]: Child connection from 172.16.1.1:44502
Sun May 21 19:04:24 2023 authpriv.info dropbear[26392]: Exit before auth from <172.16.1.1:44502>: Exited normally

# tcpdump -i tun0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes

19:04:24.102835 IP 172.16.1.1.44502 > 172.16.1.15.22: Flags [S], seq 2322423445, win 29200, options [mss 1358,sackOK,TS val 1534892693 ecr 0,nop,wscale 7], length 0
19:04:24.103137 IP 172.16.1.15.22 > 172.16.1.1.44502: Flags [S.], seq 3993150524, ack 2322423446, win 65160, options [mss 1460,sackOK,TS val 2206929105 ecr 1534892693,nop,wscale 4], length 0
19:04:24.116388 IP 172.16.1.1.44502 > 172.16.1.15.22: Flags [.], ack 1, win 229, options [nop,nop,TS val 1534892707 ecr 2206929105], length 0
19:04:24.122576 IP 172.16.1.1.44502 > 172.16.1.15.22: Flags [P.], seq 1:79, ack 1, win 229, options [nop,nop,TS val 1534892707 ecr 2206929105], length 78
19:04:24.122770 IP 172.16.1.15.22 > 172.16.1.1.44502: Flags [.], ack 79, win 4068, options [nop,nop,TS val 2206929124 ecr 1534892707], length 0
19:04:24.139822 IP 172.16.1.15.22 > 172.16.1.1.44502: Flags [P.], seq 1:411, ack 79, win 4068, options [nop,nop,TS val 2206929141 ecr 1534892707], length 410
19:04:24.141997 IP 172.16.1.15.22 > 172.16.1.1.44502: Flags [R.], seq 411, ack 79, win 4068, options [nop,nop,TS val 2206929143 ecr 1534892707], length 0
19:04:24.155042 IP 172.16.1.1.44502 > 172.16.1.15.22: Flags [.], ack 411, win 237, options [nop,nop,TS val 1534892745 ecr 2206929141], length 0
19:04:24.155243 IP 172.16.1.15.22 > 172.16.1.1.44502: Flags [R], seq 3993150935, win 0, length 0
19:04:32.406502 IP 172.16.1.1.46708 > 172.16.1.15.81: Flags [S], seq 41005334, win 29200, options [mss 1358,sackOK,TS val 1534900996 ecr 0,nop,wscale 7], length 0
19:04:32.406744 IP 172.16.1.15.81 > 172.16.1.1.46708: Flags [R.], seq 0, ack 41005335, win 0, length 0

Any clues?

Use native /etc/config/firewall.

1 Like

Sorry, don't know what you are suggesting? Can you expand on that please. Do you know why I'm seeing what I am?

@ulmwind's suggesting you reduce these commands to native OpenWrt/UCI syntax instead of trying to use the underlying iptables or nft subsystems via raw commands. This can also be done by navigating the LuCI web GUI to add firewall rules.

See:

What do you mean by the phrase "the old method" - I assume that means adding rules to /etc/config/firewall?

Basically, you're seeing this because OpenWrt switched from iptables to nft (fw4) since the version you used when you created/used your custom rules (fw3). Other options besides trying to make old iptables commands work are:

  • use nft
  • translate rules into UCI (i.e. /etc/config/firewall) - this would be the best method
5 Likes

use nft
translate rules into UCI (i.e. /etc/config/firewall) - this would be the best method

I've been trying both but nothing works, ports are blocked when forwarded.

reduce these commands to native OpenWrt/UCI syntax instead of trying to use the
underlying iptables or nft subsystems via raw commands.

This is new to me. Using uci commands to set the firewall?

This can also be done by navigating the LuCI web GUI to add firewall rules.

I don't have or use luci, it's all from the command line.

Quickly looking for info, I found something along this line.

To set this rule; -A INPUT -i tun+ -p tcp -m tcp --dport 80 -j DROP

I would have to run all of these commands??

uci add firewall rule
uci set firewall.@rule[0].name='Block HTTP traffic from VPN'
uci set firewall.@rule[0].src='vpn'
uci set firewall.@rule[0].dest='lan'
uci set firewall.@rule[0].proto='tcp'
uci set firewall.@rule[0].dport='80'
uci set firewall.@rule[0].target='DROP'

uci commit firewall
service firewall restart

That can't be right? That's so many commands for just one rule.

To keep it in an INPUT chain, you would exclude a destination zone.

And refer to new in-progress rules as firewall.@rule[-1] to refer to the most recently created rule.

Set it once, and never bother again when nftables is replaced by xyztables…

Using 'usi show firewall' shows a bunch of rules.
I added some to play with this then removed them but there were some already in there.
Might these be conflicting with iptables causing the blocking I'm seeing?

Really not liking using uci to maintain rules, it's a heck of a lot of commands to do something I usually do with just one command.

The number of rules I need aren't many yet when I look at this uci firewall output, I'm seeing a lot of stuff I don't recall entering.

It also looks like there might be stuff in there from earlier mistakes, testing etc. I've removed the obvious ones. I don't even have ipv6 interfaces on the router. Plus, my lan interface is br-lan but I see in the following rules a lot of 'lan' mentions.

$ uci show firewall
firewall.@defaults[0]=defaults
firewall.@defaults[0].syn_flood='1'
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@zone[0]=zone
firewall.@zone[0].name='lan'
firewall.@zone[0].network='lan'
firewall.@zone[0].input='ACCEPT'
firewall.@zone[0].output='ACCEPT'
firewall.@zone[0].forward='ACCEPT'
firewall.@zone[1]=zone
firewall.@zone[1].name='wan'
firewall.@zone[1].network='wan' 'wan6'
firewall.@zone[1].input='REJECT'
firewall.@zone[1].output='ACCEPT'
firewall.@zone[1].forward='REJECT'
firewall.@zone[1].masq='1'
firewall.@zone[1].mtu_fix='1'
firewall.@forwarding[0]=forwarding
firewall.@forwarding[0].src='lan'
firewall.@forwarding[0].dest='wan'
firewall.@rule[0]=rule
firewall.@rule[0].dest_port='68'
firewall.@rule[0].family='ipv4'
firewall.@rule[0].name='Block HTTP traffic from VPN'
firewall.@rule[0].proto='tcp'
firewall.@rule[0].dport='80'
firewall.@rule[0].target='DROP'
firewall.@rule[0].src='tun+'
firewall.@rule[0].dest='br-lan'
firewall.@rule[1]=rule
firewall.@rule[1].name='Allow-Ping'
firewall.@rule[1].src='wan'
firewall.@rule[1].proto='icmp'
firewall.@rule[1].icmp_type='echo-request'
firewall.@rule[1].family='ipv4'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[2]=rule
firewall.@rule[2].name='Allow-IGMP'
firewall.@rule[2].src='wan'
firewall.@rule[2].proto='igmp'
firewall.@rule[2].family='ipv4'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[3]=rule
firewall.@rule[3].name='Allow-DHCPv6'
firewall.@rule[3].src='wan'
firewall.@rule[3].proto='udp'
firewall.@rule[3].dest_port='546'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[4]=rule
firewall.@rule[4].name='Allow-MLD'
firewall.@rule[4].src='wan'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].src_ip='fe80::/10'
firewall.@rule[4].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[4].family='ipv6'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[5]=rule
firewall.@rule[5].name='Allow-ICMPv6-Input'
firewall.@rule[5].src='wan'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].family='ipv6'
firewall.@rule[5].target='ACCEPT'
firewall.@rule[6]=rule
firewall.@rule[6].name='Allow-ICMPv6-Forward'
firewall.@rule[6].src='wan'
firewall.@rule[6].dest='*'
firewall.@rule[6].proto='icmp'
firewall.@rule[6].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[6].limit='1000/sec'
firewall.@rule[6].family='ipv6'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[7]=rule
firewall.@rule[7].name='Allow-IPSec-ESP'
firewall.@rule[7].src='wan'
firewall.@rule[7].dest='lan'
firewall.@rule[7].proto='esp'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[8]=rule
firewall.@rule[8].name='Allow-ISAKMP'
firewall.@rule[8].src='wan'
firewall.@rule[8].dest='lan'
firewall.@rule[8].dest_port='500'
firewall.@rule[8].proto='udp'
firewall.@rule[8].target='ACCEPT'
firewall.@rule[9]=rule

So is this showing me that there is a conflicting firewall since I see rules in there that I never added such as icmp and others.

You overwrote the default rule 0 (Allow DHCP Renew) with your earlier commands.

firewall.@rule[0]=rule
firewall.@rule[0].name='Allow-DHCP-Renew'
firewall.@rule[0].src='wan'
firewall.@rule[0].proto='udp'
firewall.@rule[0].dest_port='68'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[0].family='ipv4'

Firewall4 in 22.03.x comes with the default rules to allow the router to function securely, same as Firewall3 did in 18.06.

What iptables rules were you using before in 18.06 that solved your problem? It might not be that hard to replicate if you share them.

These are the network interface names;
br-lan, eth0, eth0.1, eth0.2, lo and when up, tun0.

These are the rules that used to work on 18 with an example forward.

iptables -t nat -A POSTROUTING -o br-lan -j MASQUERADE
iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE
iptables -A FORWARD -i tun+ -o br-lan -j ACCEPT
iptables -A FORWARD -i br-lan -o tun+ -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -i tun+ --dport 81 -j DNAT --to-destination 192.168.1.99:80 
iptables -A INPUT -i tun+ -p tcp --destination-port 80 -j DROP

I reset the uci fbased filrewall. This is how it looks now.

 OpenWrt 22.03.3, r20028-43d71ad93e
 -----------------------------------------------------
$ uci show firewall
firewall.@defaults[0]=defaults
firewall.@defaults[0].syn_flood='1'
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@zone[0]=zone
firewall.@zone[0].name='lan'
firewall.@zone[0].network='lan'
firewall.@zone[0].input='ACCEPT'
firewall.@zone[0].output='ACCEPT'
firewall.@zone[0].forward='ACCEPT'
firewall.@zone[1]=zone
firewall.@zone[1].name='wan'
firewall.@zone[1].network='wan' 'wan6'
firewall.@zone[1].input='REJECT'
firewall.@zone[1].output='ACCEPT'
firewall.@zone[1].forward='REJECT'
firewall.@zone[1].masq='1'
firewall.@zone[1].mtu_fix='1'
firewall.@forwarding[0]=forwarding
firewall.@forwarding[0].src='lan'
firewall.@forwarding[0].dest='wan'
firewall.@rule[0]=rule
firewall.@rule[0].name='Allow-DHCP-Renew'
firewall.@rule[0].src='wan'
firewall.@rule[0].proto='udp'
firewall.@rule[0].dest_port='68'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[0].family='ipv4'
firewall.@rule[1]=rule
firewall.@rule[1].name='Allow-Ping'
firewall.@rule[1].src='wan'
firewall.@rule[1].proto='icmp'
firewall.@rule[1].icmp_type='echo-request'
firewall.@rule[1].family='ipv4'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[2]=rule
firewall.@rule[2].name='Allow-IGMP'
firewall.@rule[2].src='wan'
firewall.@rule[2].proto='igmp'
firewall.@rule[2].family='ipv4'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[3]=rule
firewall.@rule[3].name='Allow-DHCPv6'
firewall.@rule[3].src='wan'
firewall.@rule[3].proto='udp'
firewall.@rule[3].dest_port='546'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[4]=rule
firewall.@rule[4].name='Allow-MLD'
firewall.@rule[4].src='wan'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].src_ip='fe80::/10'
firewall.@rule[4].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[4].family='ipv6'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[5]=rule
firewall.@rule[5].name='Allow-ICMPv6-Input'
firewall.@rule[5].src='wan'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].family='ipv6'
firewall.@rule[5].target='ACCEPT'
firewall.@rule[6]=rule
firewall.@rule[6].name='Allow-ICMPv6-Forward'
firewall.@rule[6].src='wan'
firewall.@rule[6].dest='*'
firewall.@rule[6].proto='icmp'
firewall.@rule[6].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[6].limit='1000/sec'
firewall.@rule[6].family='ipv6'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[7]=rule
firewall.@rule[7].name='Allow-IPSec-ESP'
firewall.@rule[7].src='wan'
firewall.@rule[7].dest='lan'
firewall.@rule[7].proto='esp'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[8]=rule
firewall.@rule[8].name='Allow-ISAKMP'
firewall.@rule[8].src='wan'
firewall.@rule[8].dest='lan'
firewall.@rule[8].dest_port='500'
firewall.@rule[8].proto='udp'
firewall.@rule[8].target='ACCEPT'

Just a translation without further comments...

uci set firewall.@zone[0].masq='1'
uci add firewall zone
uci set firewall.@zone[-1].name='vpn'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'
uci set firewall.@zone[-1].device='tun+'
uci set firewall.@zone[-1].masq='1'

uci add firewall rule
uci set firewall.@rule[-1].name='DROP-HTTP-VPN-to-Router'
uci set firewall.@rule[-1].src='vpn'
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].dest_port='80'
uci set firewall.@rule[-1].family='ipv4'
uci set firewall.@rule[-1].target='DROP'

uci add firewall redirect
uci set firewall.@redirect[-1].target='DNAT'
uci set firewall.@redirect[-1].src='vpn'
uci set firewall.@redirect[-1].name='VPN-HTTP-Redirect'
uci set firewall.@redirect[-1].dest_ip='192.168.1.99'
uci set firewall.@redirect[-1].dest='lan'
uci set firewall.@redirect[-1].proto='tcp'
uci set firewall.@redirect[-1].dest_port='80'
uci set firewall.@redirect[-1].src_dport='81'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='vpn'
uci set firewall.@forwarding[-1].dest='lan'

uci add firewall forwarding
uci set firewall.@forwarding[-1].src='lan'
uci set firewall.@forwarding[-1].dest='vpn'
uci commit firewall
fw4 restart
4 Likes

If you are able to use vi, just edit /etc/config/firewall and /etc/init.d/firewall restart.... :man_shrugging:

1 Like

I put all of the uci commands in a file and ran it. Just the following error but it's working.
First, I'm floored to see this working so thank you very much for this help because I've been struggling with this on and off for weeks.

Second, I cannot hard code the firewall file because sometimes, I add/remove devices to be forwarded to so am not sure how I would keep track of that since I need a little script that receives the request then it created the rules. Since I was using iptables, this was extremely simple but I'll have to re-think how I can do this since now there will be a large number of commands.

$ ./test
cfg0edc81
cfg0f92bd
cfg103837
cfg11ad58
cfg12ad58
Section @redirect[0] (VPN-HTTP-Redirect) external address range cannot be determined, disabling reflection

So we're talking about uci right now but since you've seen that it's working now, is there some other option that is not so texty I could use? Even another firewall perhaps? I don't have any security risks really since these things run on the LAN only.

If you are absolutely sure about that, stop and disable fw4 to avoid "collisions" and run your custom iptables rules (but not using /etc/firewall.user which doesn't even exist in this version).

/etc/init.d/firewall stop; /etc/init.d/firewall disable

I assume you have kmod-ipt-nat installed.

I always want minimal security no matter what but this device is just a LAN side client that gives me a vpn tunnel to my work and some access back to the LAN.
Since the vpn is encrypted, and there is still a password on the router, and it's on the LAN, I don't have any high security risks that I can think of.

First problem is after running those uci commands, I'm now locked out and can't get back in. I rebooted it (power cycle) and no change so might have to re-install the firmware.

Running nmap shows no ports open on it at all now.

Working on that now.