Nftables bridge won't forward until I flush rules and restart firewall?

Having a strange problem here, probably of my own making...

Using a GLiNet MT2500 as a (very) simple bridge firewall. Built and running a fresh build of OpenWRT main branch:

Linux OpenWrt 6.6.32 #0 SMP Fri May 31 23:29:09 2024 aarch64 GNU/Linux`

root@OpenWrt:/# cat /etc/openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='SNAPSHOT'
DISTRIB_REVISION='r26490-8619d7af67'
DISTRIB_TARGET='mediatek/filogic'
DISTRIB_ARCH='aarch64_cortex-a53'
DISTRIB_DESCRIPTION='OpenWrt SNAPSHOT r26490-8619d7af67'
DISTRIB_TAINTS='no-all'`

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br-fw state UP qlen 1000
    link/ether 94:83:c4:27:d7:8f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br-fw state UP qlen 1000
    link/ether 94:83:c4:27:d7:90 brd ff:ff:ff:ff:ff:ff
4: br-fw: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 94:83:c4:27:d7:8f brd ff:ff:ff:ff:ff:ff
    inet6 fe80::9683:c4ff:fe27:d78f/64 scope link
       valid_lft forever preferred_lft forever

root@OpenWrt:/# nft list ruleset
table bridge filter {
        chain forward {
                type filter hook forward priority 0; policy drop;
                ether type arp accept
                iifname "eth1" accept
                ct state vmap { invalid : drop, established : accept, related : accept }
                icmp type echo-request limit rate 5/second burst 5 packets accept
                iifname "eth0" oifname "eth1" ct state new tcp dport 25 accept
        }
}

root@OpenWrt:/# cat /etc/nftables.d/bridge.sh
. /lib/functions/network.sh

network_flush_cache

nft add table bridge filter
nft flush table bridge filter

nft add chain bridge filter forward '{ type filter hook forward priority 0; policy drop; }'

nft add rule bridge filter forward ether type arp accept
nft add rule bridge filter forward iifname "eth1" accept
nft add rule bridge filter forward ct state vmap '{ established : accept, related : accept, invalid : drop }'
nft add rule bridge filter forward icmp type echo-request limit rate 5/second burst 5 packets accept
nft add rule bridge filter forward iifname "eth0" oifname "eth1" ct state new tcp dport 25 accept
root@OpenWrt:/#

root@OpenWrt:/# brctl show
bridge name     bridge id               STP enabled     interfaces
br-fw           7fff.9483c427d78f       no              eth0
                                                        eth1

root@OpenWrt:/# uci show firewall
firewall.bridge=include
firewall.bridge.path='/etc/nftables.d/bridge.sh'

# I took an axe to this to clear out unwanted inet rules...
root@OpenWrt:/# cat /usr/share/firewall4/templates/ruleset.uc
{% fw4.includes('ruleset-append') %}

Aside from the firewall issue, the device boots and works fine. The issue is, during testing, I rebooted to discover the bridge firewall won't forward any traffic until I manually flush the ruleset and restart the firewall (nft flush ruleset; service firewall restart - loading the exact same ruleset as when it boots) - then the rules "take effect".

I cobbled together the ruleset based on:

https://wiki.nftables.org/wiki-nftables/index.php/Bridge_filtering
https://openwrt.org/docs/guide-user/firewall/fw3_configurations/bridge

Grateful for help on what I've messed up here.

Why did you edit out your ruleset?
Best start is to add
counter log in place before default accept in place of default drop and then tune rules to actual traffic.
Likely you need to make both interfaces in same inet zone permitting forwarding and not configuring any IP addresses to make it like a switch. Editing "system" scripts will not stay after upgrades.

Thanks for the logging suggestion. Simple user error - I needed to allow DHCP related traffic.

I guess I thought conntrack would see DHCP traffic as "related", but maybe that's not for UDP traffic?

Currently working ruleset:

root@OpenWrt:/# nft list ruleset
table bridge filter {
        chain forward {
                type filter hook forward priority 0; policy drop;
                ether daddr ff:ff:ff:ff:ff:ff accept
                ether type arp accept
                udp sport 68 udp dport 67 accept
                udp sport 67 udp dport 68 accept
                iif "eth1" accept
                ct state vmap { invalid : drop, established : accept, related : accept }
                icmp type echo-request limit rate 5/second burst 5 packets accept
                iif "eth0" oif "eth1" ct state new tcp dport 25 accept
        }
}

I think you need echo rate limit in raw - prerouting, it is stateful and in effect you limit to "5+5 new addresses per second that ping me"
And state dispatch should be first to do the "heavy lifting" instantly.

You can collapse 2 rules around dhcp in one using tuples:

#                udp sport 68 udp dport 67 accept
#                udp sport 67 udp dport 68 accept
                 udp sport . udp dport { 68 . 67 , 67 . 68} accept
1 Like

You mean bridge prerouting? I have no IP addresses on any interface, so would ip raw be used?

https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks

Thanks for that tuple feature - that's a new one for me.

Current working ruleset:

table bridge filter {
        chain forward {
                type filter hook forward priority 0; policy drop;
                ct state vmap { invalid : drop, established : accept, related : accept }
                ether daddr ff:ff:ff:ff:ff:ff accept
                ether type arp accept
                udp sport . udp dport { 68 . 67, 67 . 68 } accept
                iif "eth1" accept
                iif "eth0" oif "eth1" ct state new tcp dport 25 accept
        }

        chain prerouting {
                type filter hook prerouting priority dstnat; policy accept;
                icmp type echo-request limit rate 5/second burst 5 packets accept
        }
}

https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks
You need raw before conntrack to rate-limit otherwise state-creating packets, and you need to accept icmp in filter for 2nd time.

looking again - I think last rule can start with state new .... iif oif ... rest assuming normal traffic pattern

1 Like

omg no, not that rate limit.
it needs to be rate over .... drop (plus the accept in main filter)

1 Like

Ok, thanks. I have some reading to do :slight_smile:

Documentation so rich, sometimes iptables-translate explains better.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.