Firewall4 / NFtables Tips and Tricks

Hi,
I am using latest Openwrt build using imagebuilder.
Question:

  • ping is not working for me from wan (I verified it using web ping tool to ping my public public IP address)

Very likely, I have error in my configuration:

root@np1:~# less /etc/config/firewall
...
config defaults
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option syn_flood '1'
        option synflood_protect '1'
        option synflood_rate '25/s'
        option synflood_burst '50'
        option drop_invalid '1'
        option flow_offloading '1'
        option flow_offloading_hw '1'
        option disable_ipv6 '0'
        option tcp_ecn '1'
        option tcp_syncookies '1'
        option tcp_window_scaling '1'
...
config rule
        option name 'Allow-ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        # option src_ip '192.168.0.0/16 10.0.0.0/8'
        option target 'ACCEPT'
...

I tried the following, but with no luck :frowning:

root@np1:~# less /etc/nftables.d/20-custom.nft
chain user_input_2a {
    ip protocol icmp icmp type echo-request counter accept
    ip protocol icmp icmp type { destination-unreachable, router-advertisement, router-solicitation, time-exceeded, parameter-problem } accept
}

chain user_input_2b {
    type filter hook input priority -900; policy accept;
    iifname @wan_interfaces jump user_input_2a
}

With # nft list ruleset command I can see:

root@np1:~# nft list ruleset
...
        chain user_input_2a {
                ip protocol icmp icmp type echo-request counter packets 0 bytes 0 accept
                ip protocol icmp icmp type { destination-unreachable, router-advertisement, router-solicitation, time-exceeded, parameter-problem } accept
        }

        chain user_input_2b {
                type filter hook input priority -900; policy accept;
                iifname @wan_interfaces jump user_input_2a
        }
...

Many thanks for your comments!

Forgot to say 2 weeks ago, thanks for the hint on the counter on my custom chain.

Here's another counter question: is there some way to turn on counters for each of the auto-generated rules/chains created to implement what's configured in /etc/config/firewall? Many but not all of the rules have counters on them in 22.03.0-rc1

I used to have bunch of the following rules in my config:

iptables -t nat -I PREROUTING -i br-lan -p udp --dport 123 -j DNAT --to 192.168.1.1

How can I translate that to fw4 /etc/config/firewall?
So far my attempt looked like below however tcpdump shows a lot of connections to different addresses.

config redirect
       option name 'IoT NTP redirect to router'
       list proto 'udp'
       option src 'IoT'
       option src_dport '123'
       option dest_port '123'
       option src_dip '!192.168.1.1'
       option dest_ip '192.168.1.1'
       option target 'DNAT'
       option dest 'IoT' # that is actually router interface 192.168.1.1

config redirect
        option name 'lan NTP redirect to router'
        list proto 'udp'
        option src 'lan'
        option src_dport '123'
        option dest_port '123'
        option src_dip '!10.0.0.1'
        option dest_ip '10.0.0.1'
        option target 'DNAT'
        option dest 'lan' # that is actually router interface 10.0.0.1

This would be awesome and can probably solve:

Could you suggest the nft analogues of the rules?

iptables -A POSTROUTING -o eth2 -t mangle -j TTL --ttl-set 64
iptables -A PREROUTING -i eth2 -t mangle -m ttl --ttl 1 -j TTL --ttl-inc 4
# /etc/nftables.d/90-mangle-ttl.nft

chain mangle_ttl_out {
    type filter hook postrouting priority mangle;
    meta nfproto ipv4 oifname eth2 ip ttl set 64
}

chain mangle_ttl_in {
    type filter hook prerouting priority mangle;
    meta nfproto ipv4 iifname eth2 ip ttl 1 ip ttl set 5
}

Notes:

  1. If you want to treat IPv6 as well, remove the meta nfproto ipv4 part.
  2. nftables does not support an equivalent to iptables' --ttl-inc yet, but since "match ttl 1, increment by 4" is just a static rewrite from TTL 1 to TTL 5 basically, a fixed nftables set expression will do the job as well.
5 Likes

Is upnp broken with firewall4?

1 Like

is there any fw4 rule to masquerade and forward all internet dns request to local dns server? i m using below port forward/redirect rule for ipv4 traffic but not able to get ipv6 working other than just blocking.

i know we cant masquerade ipv6 traffic since there is no nat. not sure if there is any option other than blocking outright, pls suggest.

config redirect
	option dest 'lan'
	option target 'DNAT'
	option src 'lan'
	option src_ip '!192.168.1.250'
	option src_dport '53'
	option name 'redirect-DNS'
1 Like

This is what I did in the past, now I just block it.

# Redirect all DNS Queries to Router (IPv6)
ip6tables -t nat -A zone_lan_prerouting -p udp -m set ! --match-set ipset-lan-pihole src --dport 53 -j DNAT --to-destination [fd57:11da:b11c::153]:53 -m comment --comment "DNS, ports 53"
ip6tables -t nat -A zone_lan_prerouting -p tcp -m set ! --match-set ipset-lan-pihole src --dport 53 -j DNAT --to-destination [fd57:11da:b11c::153]:53 -m comment --comment "DNS, ports 53"

# MASQUERADE to avoid reply from unexpected source
ip6tables -t nat -A zone_wan_postrouting -d fd57:11da:b11c::1 -p tcp --dport 53 -m comment --comment "MASQUERADE" -j MASQUERADE
ip6tables -t nat -A zone_wan_postrouting -d fd57:11da:b11c::1 -p udp --dport 53 -m comment --comment "MASQUERADE" -j MASQUERADE
3 Likes

Section config include always executed regardless of the option enabled value of this section. Is this intended behavior of fw4?

I think it was an oversight in the initial implementation since the enabled variable is present in parse_include() but not checked. I think @jow can fix it easily when he has time.

1 Like

See https://git.openwrt.org/ca7e3a1a.

2 Likes

I used to use the instructions here for ipv6 DoH blocking under fw3, but this doesn't seem to work on fw4 and gives a couple of errors - one about the reload option no longer be valid and one about not finding the ip6tables-restore command. Not sure who maintains that page, but it has always been reliable in the past so hopefully they will update in time... I don't understand enough about fw4 to adapt it.

1 Like

I am looking for some input on how to properly throttle incoming connections with 22.03(rc6).

The target is to throttle "every" incoming IP separately to have at most something like 10 connections/minute on average (maybe allowing some bursts). If they exceed, give them a "cooldown" (dropping all their packages) until they stay under the limit for a timeout (like 5mins).

Such a feature would reduce the attack-surface for an amount of SSH/SMTP/HTTP/port scannings I am seeing. I would imagine this could be a quite useful tool for many home routers, with basically just one tunable knob: "Throttle incoming connections/s to".

The LUCI rules will not work, as they apply evenly across all incoming connections (does not discriminate between source IPs). For example, I don't want to lock myself out :slight_smile:

With the "new" IP Sets features and/or nft that should be possible to do. I am taking inspiration from the instructions at: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-using_nftables_to_limit_the_amount_of_connections. It only covers IPv4 and TCP, but should be extendable to IPv6 (with mixed-v4/v6 IPset) and UDP and possibly ICMP?

Where can i find the relevant docs on how to correctly use fw4/nft/ipset under OpenWRT? Do i just start dropping nft declarations in /etc/nftables.d/? Is there an architecture document somewhere?

Does anyone already have such a thing? (I tried googling for a while :slight_smile:

fail2ban does something like that. You should look into it :slight_smile: Also, with a properly configured firewall, port scans really do not matter at all if you don't have anything listening on those ports. I wouldn't worry about it.

If you do have something listening on outside ports, such as SSH, you should reconsider your setup. Use a VPN such as wireguard that does not respond to port scans at all, and use the VPN to connect services such as SSH. That would greatly reduce your attack surface.

1 Like

This is easily done with a meter... say throttling incoming ssh

table ...{
    chain ...{
...
      meta nfproto ipv4 tcp dport 22 ct state new add @my_ssh_meter4 {ip saddr limit rate over 10/minute burst 10 } drop 
      meta nfproto ipv6 tcp dport 22 ct state new add @my_ssh_meter6 {ip6 saddr limit rate over 10/minute burst 10 } drop 
...
    }
}
3 Likes

thanks for that tip. It looks like i really should just explore nft :slight_smile:

I still struggle to find good docs on the architecture of fw4, so which files go where, when and how are they reloaded. All the docs on the wiki seem to be fw3.

Thanks for the pointer. I am not trying to hide my whole network, so VPN is really not the right thing (even though I am using WG for remote-admin access).

I am trying to make it less risky to expose services (including SSH, Home-assistant, MQTT, ...) towards the big bad internet (especially as I can get public IPv6). Connect/scan-throttles can certainly help with that -- reducing some of the more "brute" attack surface.

Yes this is a good idea and nftables meters are a great way. A brute force search at 10/min has zero chance of succeeding with decent passwords etc. I do this in my own firewall for any service on the public internet. The other thing I do is randomly subsample the resulting logged packets, because it's easily the case that I can get hundreds of attempts per minute, so I randomly sample 2-3% of them to keep the logs less messy

1 Like

Ah, you could try port-knocking to make a few services somewhat less obvious to reach... while not really a secure method (unless you essentially use single-usage knock sequences changed for every try or so) more obscurity, but could help to get your services out of the cone of typical opportunistic port scans...