openwrt icon indicating copy to clipboard operation
openwrt copied to clipboard

Firewall rules are not always evaluated sequentially

Open mnlipp opened this issue 4 weeks ago • 3 comments

Describe the bug

Firewall rules are not always evaluated sequentially.

OpenWrt version

r28739-d9340319c6

OpenWrt release

24.10.2

OpenWrt target/subtarget

ipq40xx/generic

Device

AVM FRITZ!Box 4040

Image kind

Official downloaded image

Steps to reproduce

Define an accept rule restricted to a specific zone (e.g. "lan") and a subsequent general drop rule (drop everything independent of source zone). Here's the full file. It's the default (after reset) with two rules added at the end.

config defaults
	option syn_flood '1'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'

config zone
	option name 'lan'
	list network 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'

config zone
	option name 'wan'
	list network 'wan'
	list network 'wan6'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config rule
	option src 'lan'
	option dest 'wan'
	option name 'Allow DNS from LAN'
	option dest_port '53'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option src '*'
	option dest 'wan'
	option name 'Deny direct DNS as default'
	option dest_port '53'
	option target 'DROP'

Actual behaviour

The packets from the source zone that should be accepted ("lan") are dropped.

Expected behaviour

The packets from the source zone that should be accepted ("lan") should be accepted.

Additional info

Here's the generated nftable:

table inet fw4 {
	chain input {
		type filter hook input priority filter; policy drop;
		iif "lo" accept comment "!fw4: Accept traffic from loopback"
		ct state vmap { established : accept, related : accept } comment "!fw4: Handle inbound flows"
		tcp flags & (fin | syn | rst | ack) == syn jump syn_flood comment "!fw4: Rate limit TCP syn packets"
		iifname "br-lan" jump input_lan comment "!fw4: Handle lan IPv4/IPv6 input traffic"
		iifname "wan" jump input_wan comment "!fw4: Handle wan IPv4/IPv6 input traffic"
		jump handle_reject
	}

	chain forward {
		type filter hook forward priority filter; policy drop;
		ct state vmap { established : accept, related : accept } comment "!fw4: Handle forwarded flows"
		tcp dport 53 counter jump drop_to_wan comment "!fw4: Deny direct DNS as default"
		udp dport 53 counter jump drop_to_wan comment "!fw4: Deny direct DNS as default"
		iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
		iifname "wan" jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic"
		jump handle_reject
	}

	chain output {
		type filter hook output priority filter; policy accept;
		oif "lo" accept comment "!fw4: Accept traffic towards loopback"
		ct state vmap { established : accept, related : accept } comment "!fw4: Handle outbound flows"
		oifname "br-lan" jump output_lan comment "!fw4: Handle lan IPv4/IPv6 output traffic"
		oifname "wan" jump output_wan comment "!fw4: Handle wan IPv4/IPv6 output traffic"
	}

	chain prerouting {
		type filter hook prerouting priority filter; policy accept;
		iifname "br-lan" jump helper_lan comment "!fw4: Handle lan IPv4/IPv6 helper assignment"
	}

	chain handle_reject {
		meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic"
		reject comment "!fw4: Reject any other traffic"
	}

	chain syn_flood {
		limit rate 25/second burst 50 packets return comment "!fw4: Accept SYN packets below rate-limit"
		drop comment "!fw4: Drop excess packets"
	}

	chain input_lan {
		jump accept_from_lan
	}

	chain output_lan {
		jump accept_to_lan
	}

	chain forward_lan {
		meta nfproto ipv4 tcp dport 53 counter jump accept_to_wan comment "!fw4: Allow DNS from LAN"
		meta nfproto ipv4 udp dport 53 counter jump accept_to_wan comment "!fw4: Allow DNS from LAN"
		jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
		jump accept_to_lan
	}

	chain helper_lan {
	}

	chain accept_from_lan {
		iifname "br-lan" counter accept comment "!fw4: accept lan IPv4/IPv6 traffic"
	}

	chain accept_to_lan {
		oifname "br-lan" counter accept comment "!fw4: accept lan IPv4/IPv6 traffic"
	}

	chain input_wan {
		meta nfproto ipv4 udp dport 68 counter accept comment "!fw4: Allow-DHCP-Renew"
		icmp type echo-request counter accept comment "!fw4: Allow-Ping"
		meta nfproto ipv4 meta l4proto igmp counter accept comment "!fw4: Allow-IGMP"
		meta nfproto ipv6 udp dport 546 counter accept comment "!fw4: Allow-DHCPv6"
		ip6 saddr fe80::/10 icmpv6 type . icmpv6 code { mld-listener-query . 0, mld-listener-report . 0, mld-listener-done . 0, mld2-listener-report . 0 } counter accept comment "!fw4: Allow-MLD"
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply, nd-router-solicit, nd-router-advert } limit rate 1000/second burst 5 packets counter accept comment "!fw4: Allow-ICMPv6-Input"
		icmpv6 type . icmpv6 code { packet-too-big . 0, parameter-problem . 0, nd-neighbor-solicit . 0, nd-neighbor-advert . 0, parameter-problem . 1 } limit rate 1000/second burst 5 packets counter accept comment "!fw4: Allow-ICMPv6-Input"
		jump reject_from_wan
	}

	chain output_wan {
		jump accept_to_wan
	}

	chain forward_wan {
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply } limit rate 1000/second burst 5 packets counter accept comment "!fw4: Allow-ICMPv6-Forward"
		icmpv6 type . icmpv6 code { packet-too-big . 0, parameter-problem . 0, parameter-problem . 1 } limit rate 1000/second burst 5 packets counter accept comment "!fw4: Allow-ICMPv6-Forward"
		meta l4proto esp counter jump accept_to_lan comment "!fw4: Allow-IPSec-ESP"
		udp dport 500 counter jump accept_to_lan comment "!fw4: Allow-ISAKMP"
		jump reject_to_wan
	}

	chain accept_to_wan {
		meta nfproto ipv4 oifname "wan" ct state invalid counter drop comment "!fw4: Prevent NAT leakage"
		oifname "wan" counter accept comment "!fw4: accept wan IPv4/IPv6 traffic"
	}

	chain reject_from_wan {
		iifname "wan" counter jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain reject_to_wan {
		oifname "wan" counter jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain dstnat {
		type nat hook prerouting priority dstnat; policy accept;
	}

	chain srcnat {
		type nat hook postrouting priority srcnat; policy accept;
		oifname "wan" jump srcnat_wan comment "!fw4: Handle wan IPv4/IPv6 srcnat traffic"
	}

	chain srcnat_wan {
		meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 wan traffic"
	}

	chain raw_prerouting {
		type filter hook prerouting priority raw; policy accept;
	}

	chain raw_output {
		type filter hook output priority raw; policy accept;
	}

	chain mangle_prerouting {
		type filter hook prerouting priority mangle; policy accept;
	}

	chain mangle_postrouting {
		type filter hook postrouting priority mangle; policy accept;
		oifname "wan" tcp flags & (fin | syn | rst) == syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 egress MTU fixing"
	}

	chain mangle_input {
		type filter hook input priority mangle; policy accept;
	}

	chain mangle_output {
		type route hook output priority mangle; policy accept;
	}

	chain mangle_forward {
		type filter hook forward priority mangle; policy accept;
		iifname "wan" tcp flags & (fin | syn | rst) == syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 ingress MTU fixing"
	}

	chain drop_to_wan {
		oifname "wan" counter drop comment "!fw4: drop wan IPv4/IPv6 traffic"
	}
}

As can be seen, chain forward drops the traffic to port 53 before it jumps to forward_lan. This does not match your expectations when you follow the sequence of the firewall rules, because there we have the acceptance …

config rule
	option src 'lan'
	option dest 'wan'
	option name 'Allow DNS from LAN'
	option dest_port '53'
	option target 'ACCEPT'
	option family 'ipv4'

... before the drop:

config rule
	option src '*'
	option dest 'wan'
	option name 'Deny direct DNS as default'
	option dest_port '53'
	option target 'DROP'

Diffconfig


Terms

  • [x] I am reporting an issue for OpenWrt, not an unsupported fork.

mnlipp avatar Dec 14 '25 20:12 mnlipp

Invalid Version reported. 24.10.2 Is this from a clean repository?

github-actions[bot] avatar Dec 14 '25 20:12 github-actions[bot]

Invalid Release reported. r28739-d9340319c6 Is this from a clean repository?

github-actions[bot] avatar Dec 14 '25 20:12 github-actions[bot]

Mixed up version and release.

mnlipp avatar Dec 14 '25 20:12 mnlipp