Firewall4 / NFtables Tips and Tricks

@ivanich - Wireguard on udp here without issue. I am running a snapshot I built today wherein this fix is applied. The fact that your experiencing differences tcp vs udp suggests that issue is not affecting you.

1 Like

I updated this morning, so have the latest changes and my UDP/53 port to allow inbound DNS traffic is no longer working, but the TCP/53 rule works fine, which sounds very similar to your wireguard/openvpn issue

I can't for the life of me figure out what's wrong, I'm not seeing any matches on the udp rule, but I don't see traffic being dropped with logging enabled either...

Actually, I think for some reason the traffic is being forwarded to an internal host....

So in my case, I had the below rule in /etc/config/firewall to forward both tcp and udp 60002 to the internal host

config redirect
        option target 'DNAT'
        option src 'wan'
        option dest 'lan'
        option proto 'tcp udp'
        option dest_ip '192.168.1.2'
        option dest_port '60002'
        option src_dport '60002'

fw4 translated it to the below, it got the tcp rule right, but the udp rule is missing a port number so all udp traffic was forwarded to the internal host. I've worked around the issue by having separate rules for tcp and udp and as a bonus, nft makes a little more sense than it did this time yesterday :slight_smile:

 meta nfproto ipv4 tcp dport 60002 counter packets 9 bytes 476 dnat ip to 192.168.1.2:60002 
 meta nfproto ipv4 meta l4proto udp counter packets 12 bytes 1538 dnat ip to 192.168.1.2 
2 Likes

Can't reproduce it using test cases, but maybe there's another bug lurking there. Which target/device do you run OpenWrt on exactly?

@jow @noblem @darksky

Just another friendly request for moving issue discussion to separate threads, please :slight_smile: Would be great to get this topic back to its original intent. Thanks!

Done and sorry :slight_smile:

In the spirit of the original subject, hopefully the below will be of use to anyone new to nft and trying to do a bit of troubleshooting...

  • nft list tables This ones is pretty self explanatory and most people will only have table inet fw4, unless rules have also been added via iptables-nft
  • nft list table inet fw4 Lists everything in a given table
  • nft list ruleset Similar to the above, but lists everything
  • nft list chain inet fw4 dstnat_wan Lists the contents of a specific chain within the table

It's not quite as obvious as iptables, at least to me, but a lot of chains have counters which show packets/bytes matched, but only if they've been added with a counter. Logging also works, at least on the WAN side, by adding option log '0' to the wan zone in the firewall config file, which might help anyone trying to debug issues

Finally

  • nft add rule inet fw4 input udp dport 53 counter accept Adds a rule, however it's appended to the end of the chain
  • nft add rule inet fw4 input position 10 udp dport 53 counter accept Adds the same rule, but after the the one in position 10 (Adding -a to the list commands gives you the handle/position)
  • nft delete rule inet fw4 input handle 108 Delete a rule with the given handle, which seems to be the only way to delete a rule via nft
4 Likes

No worries! This is great info you just shared and I'm sure it will help a lot of others as they dive into this new fw4 journey!

1 Like

In the spirit of the thread: a tip for debugging rules allowing (for example) SSH access from wan:

nft add rule inet fw4 mangle_prerouting tcp dport 22 meta nftrace set 1
nft monitor

Any packet matching the rule in the first line (tcp dport 22 in the mangle_prerouting chain) will then be traced through the remaining nftables chains, which is handy for debugging rules and understanding packet flows.

1 Like

sorry for the stupid question, but do we expect firewall4 to be, first or then, a clean drop-in replacement for firewall3? i mean, do we expect a new firmware to work with old config?
i'm quite scared because now i have a lot of ipset-based rules that, as far as i have understood, are no more working with firewall4 (for dnmasq-full incompatibility?) so i'd like to know if i have to start rewriting anything from scratch or it will magically work, first or then :slight_smile:
thanks

I think the intent is a drop-in replacement but there might be some headaches for users with custom stuff. Stick with the official release if you want to wait for bugs to be identified and fixed or help out with snapshot builds.

oh well i already tried with a master and i got no NSS acceleration and everythink stuck for ipset not working :slight_smile: so at the moment i'd need to really start from scratch, and to be honest i haven't understood if some steps forward were made on ipset management ->

I'd like to help, but sadly i'm not able :slight_smile:
(i also have some specific iptables custom rules in my firewall, but i know i'll have to review them, it's the basic compatibility with full packages that stops me..)

There is not yet a stable dnsmasq release that supports nftables sets, but it will come in the next 2.87 release whenever it is done.

2 Likes

Switching to firewall4 I needed to replace my /etc/firewall.user that does DNS redirecting/enforcing for clients to use pihole (or as I do, dnsmasq on another server using an addn-hosts file generated from the StevenBlack blocklist as used by pihole and also the SmartTV blocklists).

/etc/nftables.d/20-dns-adblock.nft

# PIHOLE/DNSMASQ running on 192.168.1.10 2001:1234:abcd:5678::10

chain dns_adblock {
  # Connections to/from pihole/dnsmasq server needs no filtering
  ip saddr 192.168.1.10 return
  ip daddr 192.168.1.10 return
  # Clients outwith this (DHCP) range are unfiltered
  ip saddr != 192.168.1.50-192.168.1.200 return
  # IPv6 is tricky as even if hosts are configured with static address they can still
  # use non-sequential local and random privacy addresses so filter by MAC address
  # Connection from pihole/dnsmasq server needs no filtering
  ether saddr ab:cd:ef:12:34:56 return
  meta mark set 0x53
  dnat ip to 192.168.1.10
  dnat ip6 to 2001:1234:abcd:5678::10
}

chain dstnat_dns {
 type nat hook prerouting priority -99; policy accept;
 iifname "br-lan" udp dport 53 jump dns_adblock
 iifname "br-lan" tcp dport 53 jump dns_adblock
}

chain srcnat_dns {
 type nat hook postrouting priority 101; policy accept;
 meta mark 0x53 masquerade
}

With nftables you can have multiple hooks to the same hook and if the priority is higher than the official firewall4 entry it will be processed after. Keep the "policy accept" the same. Makes it easy as you can keep it separate without having to reference firewall4 chains.

As DoH is hard to block the easiest option, with normal firewall rules, is to reject connections to Google DNS address 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 and 2001:4860:4860::8844. Easily circumventable but will block most nefarious Android system, apps and smart TVs that seem to default to trying this to ensure their advertising gets through. And we don't want Google spying anyway...

Last note, the firewall4 dstnat chain shows "priority dstnat" which nft seems to translate from default NF_IP_PRI_NAT_DST (-100) and similarly for srcnat chain which shows "priority srcnat" from default NF_IP_PRI_NAT_SRC (100). With our above rules, -99 gets written as "priority dstnat + 1" and 101 shows "priority srcnat + 1". Confused me for a short while that it wasn't showing as a number.

1 Like

As DoH is hard to block the easiest option, with normal firewall rules, is to reject connections to Google DNS address 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 and 2001:4860:4860::8844. Easily circumventable but will block most nefarious Android system, apps and smart TVs that seem to default to trying this to ensure their advertising gets through. And we don't want Google spying anyway...

You can set your pihole DNS server as default for router, create alias interface with google DNS address, and you're good to go. No problems with firewall rules.

config interface 'gDNS'
        option device '@loopback'
        option proto 'static'
        option ipaddr '8.8.8.8/32 8.8.4.4/32'
        option ipv6 '0'

1 Like

Only setting an interfaces custom DNS server (which sets DHCP option 6 for DNS or via dnsmasq entries for a per client setting) will not block anybody trying to use their own DNS - you need firewall rules to force it.

3 Likes

How could I do that?

If you wanted to redirect DNS (port 53) destined for any external DNS IP to your OpenWrt's internal DNS service:

## masquerading for ipv4 output on WAN
## assume eth1 is LAN interface
table ip masq {
    chain masqin {
        type nat hook prerouting priority 0; policy accept;

        #"if you want to hijack all DNS to go to the router's port 53"
        iifname eth1 th dport domain counter redirect to domain
    }
}

Or if you wanted to block DNS and NTP (for example) to all external servers:

## assume eth0 is WAN interface
## assume eth1 is LAN interface
table inet filter {
    chain forward {
        type filter hook forward priority 0; policy drop;

        iifname lo accept

        iifname eth1 th dport { domain, ntp } oifname eth0 reject comment "Reject external DNS and NTP"
        iifname eth1 oifname eth0 accept comment "Allow inside to forward to WAN"
        counter log prefix "FIREWALL FAIL FORWARDING: " drop
    }
}
1 Like

You can also create a comparable rule in firewall (showing the rule Adblock adds):

config redirect 'adblock_lan53'
        option name 'Adblock DNS (lan, 53)'
        option src 'lan'
        option proto 'tcp udp'
        option src_dport '53'
        option dest_port '53'
        option target 'DNAT'

This translates to:

chain dstnat {
      type nat hook prerouting priority dstnat; policy accept;
      iifname "eth0" jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
}

chain dstnat_lan {
      meta nfproto ipv4 tcp dport 53 counter redirect to 53 comment "!fw4: Adblock DNS (lan, 53)"
      meta nfproto ipv4 udp dport 53 counter redirect to 53 comment "!fw4: Adblock DNS (lan, 53)"
}
1 Like

I have a similar question about dns prerouting (pihole ads block). I used these iptables rules:

iptables -t nat -A PREROUTING -i br-lan ! -s 192.168.10.12 -p tcp --dport 53 -j DNAT --to 192.168.10.12:53
iptables -t nat -A PREROUTING -i br-lan ! -s 192.168.10.12 -p udp --dport 53 -j DNAT --to 192.168.10.12:53
iptables -t nat -A POSTROUTING -j MASQUERADE

I upgraded to a new version of openwrt with nftables fw4.
How can I implement these rules to nftables rule? chain?

I think a normal firewall rule like this should work.

config redirect
        option target 'DNAT'
        option name 'Pi-Hole Intecept'
        option src 'lan'
        option src_ip '!192.168.10.12'
        option dest 'lan'
        option dest_ip '192.168.10.12'
        option src_dport '53'
        option dest_port '53'