Firewall4 / NFtables Tips and Tricks

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'

Actually those two firewall rules didn't work for me. Using Cloudflare does not block ads (the router has NextDNS as upstream servers). The closest thing that worked for me was to block all connections to the WAN on port 53.

This is for port forwading. It is better to set it over nat ? or nftables like this:

nft add rule ip nat PREROUTING iifname "br-lan" ip saddr != 192.168.10.12 tcp dport 53 counter dnat to 192.168.10.12:53
nft add rule ip nat PREROUTING iifname "br-lan" ip saddr != 192.168.10.12 udp dport 53 counter dnat to 192.168.10.12:53
nft add rule ip nat POSTROUTING counter masquerade

try using PORT FORWARDING :slight_smile:

This is what I use to intercept port 53 DNS traffic

Does it really work for you?

yes this is working properly

How do you know that the router's DNS is actually being used and not the one entered manually on the client device?

Assuming you are on the LAN zone and you have a port forward rule, check the "counters" of the rule you have created. you can do this on the client

nslookup openwrt.org 8.8.8.8

and then try issuing this on the router

nft -a list chain inet fw4 dstnat_lan

If the counter just got incremented, your rule worked and you are using your own DNS server.

Another trick is to lookup a host that can only be found in your DNS server. If it is successful, your rule works.

You can also test it via

2 Likes