Fw4 error on loading custom filter chain after device booted on OpenWrt One running firmware v24.10.0-rc6

I've got few nftable rules in the file /etc/nftables.d/10-custom-filter-chains.nft, here's its content:

## Above are comments and are deleted.

chain mangle_prerouting {
	ip saddr 192.168.1.123/32 meta mark set 0x01;
	ip6 saddr fd01:2345:abcd::123/128 meta mark set 0x01;
}

The problem is that every time the devices boots the firewall failes to apply these rules like this:

root@OpenWrt:~# fw4 reload
Automatically including '/usr/share/nftables.d/table-post/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/dstnat/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/forward/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/srcnat/20-miniupnpd.nft'
/dev/stdin:177:3-45: Error: Chain of type "filter" is not supported, perhaps kernel support is missing?
		type filter hook prerouting priority mangle; policy accept;
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

By moving that nft file to somewhere else and then run fw4 reload the firewall will work again. Next, put the nft file back and run fw4 reload, this time fw4 proceeds without errors.
The firmware is built on the tag v24.10.0-rc6, and here's the content of the .config:

Build config of the firmware of OpenWrt One v24.10.0-rc6
CONFIG_TARGET_mediatek=y
CONFIG_TARGET_mediatek_filogic=y
CONFIG_TARGET_mediatek_filogic_DEVICE_openwrt_one=y
CONFIG_BUSYBOX_CUSTOM=y
CONFIG_BATMAN_ADV_BATMAN_V=y
CONFIG_BATMAN_ADV_BLA=y
CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_BUSYBOX_CONFIG_ASH_SLEEP=y
CONFIG_BUSYBOX_CONFIG_BASE32=y
CONFIG_BUSYBOX_CONFIG_BASE64=y
CONFIG_BUSYBOX_CONFIG_BLKID=y
CONFIG_BUSYBOX_CONFIG_BUSYBOX=y
CONFIG_BUSYBOX_CONFIG_FDISK=y
CONFIG_BUSYBOX_CONFIG_FEATURE_BLKID_TYPE=y
CONFIG_BUSYBOX_CONFIG_FEATURE_DD_STATUS=y
CONFIG_BUSYBOX_CONFIG_FEATURE_DF_FANCY=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_ASK_TERMINAL=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVE_ON_EXIT=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_VI=y
CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_WINCH=y
CONFIG_BUSYBOX_CONFIG_FEATURE_FIND_EXEC_PLUS=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_ASK_TERMINAL=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_BRACKETS=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_FLAGS=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_REGEXP=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_TRUNCATE=y
CONFIG_BUSYBOX_CONFIG_FEATURE_LESS_WINCH=y
CONFIG_BUSYBOX_CONFIG_FEATURE_REVERSE_SEARCH=y
CONFIG_BUSYBOX_CONFIG_FEATURE_UDHCP_8021Q=y
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_8BIT=y
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_COLON_EXPAND=y
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO=y
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE=y
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=32
CONFIG_BUSYBOX_CONFIG_FEATURE_VI_VERBOSE_STATUS=y
CONFIG_BUSYBOX_CONFIG_FLOAT_DURATION=y
CONFIG_BUSYBOX_CONFIG_LSPCI=y
CONFIG_BUSYBOX_CONFIG_LSUSB=y
CONFIG_BUSYBOX_CONFIG_PIE=y
CONFIG_BUSYBOX_CONFIG_REALPATH=y
CONFIG_BUSYBOX_CONFIG_RFKILL=y
CONFIG_BUSYBOX_CONFIG_SEEDRNG=y
CONFIG_BUSYBOX_CONFIG_VOLUMEID=y
CONFIG_BUSYBOX_CONFIG_XXD=y
CONFIG_OPENSSL_ENGINE=y
CONFIG_OPENSSL_WITH_ASM=y
CONFIG_OPENSSL_WITH_CHACHA_POLY1305=y
CONFIG_OPENSSL_WITH_CMS=y
CONFIG_OPENSSL_WITH_DEPRECATED=y
CONFIG_OPENSSL_WITH_ERROR_MESSAGES=y
CONFIG_OPENSSL_WITH_IDEA=y
CONFIG_OPENSSL_WITH_MDC2=y
CONFIG_OPENSSL_WITH_PSK=y
CONFIG_OPENSSL_WITH_SEED=y
CONFIG_OPENSSL_WITH_SRP=y
CONFIG_OPENSSL_WITH_TLS13=y
CONFIG_OPENSSL_WITH_WHIRLPOOL=y
CONFIG_PACKAGE_batctl-default=y
CONFIG_PACKAGE_cgi-io=y
CONFIG_PACKAGE_ip-full=y
# CONFIG_PACKAGE_iw is not set
CONFIG_PACKAGE_iw-full=y
CONFIG_PACKAGE_kmod-batman-adv=y
CONFIG_PACKAGE_kmod-crypto-lib-chacha20=y
CONFIG_PACKAGE_kmod-crypto-lib-chacha20poly1305=y
CONFIG_PACKAGE_kmod-crypto-lib-curve25519=y
CONFIG_PACKAGE_kmod-crypto-lib-poly1305=y
CONFIG_PACKAGE_kmod-fs-squashfs=y
CONFIG_PACKAGE_kmod-input-core=y
CONFIG_PACKAGE_kmod-lib-crc16=y
CONFIG_PACKAGE_kmod-nf-tproxy=y
CONFIG_PACKAGE_kmod-nft-arp=y
CONFIG_PACKAGE_kmod-nft-bridge=y
CONFIG_PACKAGE_kmod-nft-tproxy=y
CONFIG_PACKAGE_kmod-rfkill=y
CONFIG_PACKAGE_kmod-tun=y
CONFIG_PACKAGE_kmod-udptunnel4=y
CONFIG_PACKAGE_kmod-udptunnel6=y
CONFIG_PACKAGE_kmod-wireguard=y
CONFIG_PACKAGE_libblkid=y
CONFIG_PACKAGE_libbpf=y
CONFIG_PACKAGE_libcap=y
CONFIG_PACKAGE_libcap-ng=y
CONFIG_PACKAGE_libelf=y
CONFIG_PACKAGE_libevent2-core=y
CONFIG_PACKAGE_liblucihttp=y
CONFIG_PACKAGE_liblucihttp-ucode=y
CONFIG_PACKAGE_libmount=y
CONFIG_PACKAGE_libncurses=y
CONFIG_PACKAGE_libopenssl=y
CONFIG_PACKAGE_librt=y
CONFIG_PACKAGE_libsmartcols=y
CONFIG_PACKAGE_libuuid=y
CONFIG_PACKAGE_libuv=y
CONFIG_PACKAGE_libwebsockets-full=y
CONFIG_PACKAGE_libwolfssl=y
CONFIG_PACKAGE_lsblk=y
CONFIG_PACKAGE_luci-app-firewall=y
CONFIG_PACKAGE_luci-app-ttyd=y
CONFIG_PACKAGE_luci-app-upnp=y
CONFIG_PACKAGE_luci-base=y
CONFIG_PACKAGE_luci-lib-uqr=y
CONFIG_PACKAGE_luci-light=y
CONFIG_PACKAGE_luci-mod-admin-full=y
CONFIG_PACKAGE_luci-mod-network=y
CONFIG_PACKAGE_luci-mod-status=y
CONFIG_PACKAGE_luci-mod-system=y
CONFIG_PACKAGE_luci-proto-batman-adv=y
CONFIG_PACKAGE_luci-proto-ipv6=y
CONFIG_PACKAGE_luci-proto-ppp=y
CONFIG_PACKAGE_luci-proto-wireguard=y
CONFIG_PACKAGE_luci-theme-bootstrap=y
CONFIG_PACKAGE_miniupnpd-nftables=y
CONFIG_PACKAGE_openssh-sftp-server=y
CONFIG_PACKAGE_resolveip=y
CONFIG_PACKAGE_rpcd=y
CONFIG_PACKAGE_rpcd-mod-file=y
CONFIG_PACKAGE_rpcd-mod-iwinfo=y
CONFIG_PACKAGE_rpcd-mod-luci=y
CONFIG_PACKAGE_rpcd-mod-rrdns=y
CONFIG_PACKAGE_rpcd-mod-ucode=y
CONFIG_PACKAGE_terminfo=y
CONFIG_PACKAGE_tmux=y
CONFIG_PACKAGE_ttyd=y
CONFIG_PACKAGE_ucode-mod-html=y
CONFIG_PACKAGE_ucode-mod-math=y
CONFIG_PACKAGE_uhttpd=y
CONFIG_PACKAGE_uhttpd-mod-ubus=y
CONFIG_PACKAGE_wireguard-tools=y
# CONFIG_PACKAGE_wpad-basic-mbedtls is not set
CONFIG_PACKAGE_wpad-wolfssl=y
CONFIG_PACKAGE_zlib=y
CONFIG_USE_RFKILL=y
CONFIG_WOLFSSL_HAS_NO_HW=y
CONFIG_WPA_RFKILL_SUPPORT=y
CONFIG_WPA_WOLFSSL=y
# CONFIG_PACKAGE_kmod-crypto-kpp is not set

Can you show fw4 print when it fails, namely lines before "type filer hook..." as in shown parse error ?
These files are part of miniupnpd-nftables package, kind of harmless interjection in fw ruleset even if restored from backup via careless sysupgrade.

Add

ubus call system board
cat /etc/config/firewall
cat /etc/config/network
1 Like

Add the hook in your custom file:

chain mangle_prerouting {
    type filter hook prerouting priority mangle; policy accept;
	ip saddr 192.168.1.123/32 meta mark set 0x01;
	ip6 saddr fd01:2345:abcd::123/128 meta mark set 0x01;
}
1 Like

fw3 print should expose what breaks syntax of ruleset
mentioned hook is empty by default, maybe some newlines in other include before it.

EDIT: likely to do with manual config applied to utilise tproxy.

root@router:~# cat test.nft 
table inet fw4 {

chain mangle_prerouting {
        ip saddr 192.168.1.123/32 meta mark set 0x01;
        ip6 saddr fd01:2345:abcd::123/128 meta mark set 0x01;
}

chain mangle_prerouting {
    type filter hook prerouting priority mangle; policy accept;
}
}
root@router:~# nft -c -f test.nft 
test.nft:9:5-47: Error: Chain of type "filter" is not supported, perhaps kernel support is missing?
    type filter hook prerouting priority mangle; policy accept;

Now add the hook:

root@router:~# cat test.nft 
table inet fw4 {

chain mangle_prerouting {
    type filter hook prerouting priority mangle; policy accept;
        ip saddr 192.168.1.123/32 meta mark set 0x01;
        ip6 saddr fd01:2345:abcd::123/128 meta mark set 0x01;
}

chain mangle_prerouting {
    type filter hook prerouting priority mangle; policy accept;
}
}
root@router:~# nft -c -f test.nft 
root@router:~#

No more errors.

2 Likes

Interesting, should fw4 ad decors or minipnp shift hook +-10 from current.
(upon op-s confirmation)

Here are the information you asked:

Output of command: fw4 print
Automatically including '/usr/share/nftables.d/table-post/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/dstnat/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/forward/20-miniupnpd.nft'
Automatically including '/usr/share/nftables.d/chain-post/srcnat/20-miniupnpd.nft'
table inet fw4
flush table inet fw4

table inet fw4 {
	#
	# Defines
	#

	define lan_devices = { "br-lan" }
	define lan_subnets = { 192.168.1.0/24, [redacted: inet address]::/60, fdcf:4d5e:8ba6::/60 }

	define wan_devices = { "pppoe-wan", "eth1" }
	define wan_subnets = { 10.5.75.71, fe80::dc74:c752:42e:fe30, [redacted: inet address]::/64 }


	#
	# User includes
	#

	include "/etc/nftables.d/*.nft"


	#
	# Filter rules
	#

	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 { "pppoe-wan", "eth1" } 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"
		iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
		iifname { "pppoe-wan", "eth1" } jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic"
		include "/usr/share/nftables.d/chain-post/forward/20-miniupnpd.nft"
		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 { "pppoe-wan", "eth1" } 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 with icmpx type port-unreachable 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 {
		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"
		meta nfproto ipv4 icmp type 8 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 { 130 . 0, 131 . 0, 132 . 0, 143 . 0 } counter accept comment "!fw4: Allow-MLD"
		meta nfproto ipv6 icmpv6 type { 128, 129, 1, 3, 133, 134 } limit rate 1000/second counter accept comment "!fw4: Allow-ICMPv6-Input"
		meta nfproto ipv6 icmpv6 type . icmpv6 code { 2 . 0, 4 . 0, 4 . 1, 135 . 0, 136 . 0 } limit rate 1000/second counter accept comment "!fw4: Allow-ICMPv6-Input"
		jump reject_from_wan
	}

	chain output_wan {
		jump accept_to_wan
	}

	chain forward_wan {
		meta nfproto ipv6 icmpv6 type { 128, 129, 1, 3 } limit rate 1000/second counter accept comment "!fw4: Allow-ICMPv6-Forward"
		meta nfproto ipv6 icmpv6 type . icmpv6 code { 2 . 0, 4 . 0, 4 . 1 } limit rate 1000/second 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"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] tcp dport [redacted] counter jump accept_to_lan comment "!fw4: Allow i2p inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] udp dport [redacted] counter jump accept_to_lan comment "!fw4: Allow i2p inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] tcp dport [redacted] counter jump accept_to_lan comment "!fw4: Allow qbittorrent inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] udp dport [redacted] counter jump accept_to_lan comment "!fw4: Allow qbittorrent inbound"
		jump reject_to_wan
	}

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

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

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


	#
	# NAT rules
	#

	chain dstnat {
		type nat hook prerouting priority dstnat; policy accept;
		include "/usr/share/nftables.d/chain-post/dstnat/20-miniupnpd.nft"
	}

	chain srcnat {
		type nat hook postrouting priority srcnat; policy accept;
		oifname { "pppoe-wan", "eth1" } jump srcnat_wan comment "!fw4: Handle wan IPv4/IPv6 srcnat traffic"
		include "/usr/share/nftables.d/chain-post/srcnat/20-miniupnpd.nft"
	}

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


	#
	# Raw rules (notrack)
	#

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

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


	#
	# Mangle rules
	#

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

	chain mangle_postrouting {
		type filter hook postrouting priority mangle; policy accept;
		oifname { "pppoe-wan", "eth1" } tcp flags syn / syn,fin,rst 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 { "pppoe-wan", "eth1" } tcp flags syn / syn,fin,rst tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 ingress MTU fixing"
	}

	include "/usr/share/nftables.d/table-post/20-miniupnpd.nft"
}
Output of command: ubus call system board
{
	"kernel": "6.6.73",
	"hostname": "OpenWrt",
	"system": "ARMv8 Processor rev 4",
	"model": "OpenWrt One",
	"board_name": "openwrt,one",
	"rootfs_type": "squashfs",
	"release": {
		"distribution": "OpenWrt",
		"version": "24.10.0-rc6",
		"revision": "r28388-58d0057481",
		"target": "mediatek/filogic",
		"description": "OpenWrt 24.10.0-rc6 r28388-58d0057481",
		"builddate": "1737575574"
	}

Content of file: /etc/config/firewall

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 name 'Allow i2p inbound'
	option family 'ipv6'
	option src 'wan'
	option dest 'lan'
	option dest_port '[redacted]'
	option target 'ACCEPT'
	list dest_ip '::[redacted]/-64'

config rule
	option name 'Allow qbittorrent inbound'
	option family 'ipv6'
	option src 'wan'
	option dest 'lan'
	option dest_port '[redacted]'
	option target 'ACCEPT'
	list dest_ip '::[redacted]/-64'
Content of file: /etc/config/network
config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fdcf:4d5e:8ba6::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'wan'
	option device 'eth1'
	option proto 'pppoe'
	option username '[redacted]'
	option password '[redacted]'
	option ipv6 'auto'
	option keepalive '0 1'

config interface 'wan6'
	option device 'eth1'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'
	option norelease '1'

config rule
	option lookup 'v2tproxy'
	option mark '0x1'

config rule6
	option lookup 'v2tproxy'
	option mark '0x1'

config route
	option target '0.0.0.0/0'
	option gateway '192.168.1.[redacted]'
	option table 'v2tproxy'

config route6
	option target '::/0'
	option gateway 'fdcf:4d5e:8ba6::[redacted]'
	option table 'v2tproxy'

How tproxy is hooked into nftables?
check "nft list ruleset" (review for fixed public ips, call them ZZZ}

This solved the issue. But it's weird that fw4 reload gave an error that's obscure.

Running command nft list ruleset right after reboot gives empty output.

Running command nft list ruleset after moving the nft file away gives output:

Output of: nft list ruleset
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 { "eth1", "pppoe-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"
		iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
		iifname { "eth1", "pppoe-wan" } jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic"
		jump upnp_forward comment "Hook into miniupnpd forwarding chain"
		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 { "eth1", "pppoe-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 {
		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 packets 6 bytes 512 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
	}

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

	chain input_wan {
		meta nfproto ipv4 udp dport 68 counter packets 0 bytes 0 accept comment "!fw4: Allow-DHCP-Renew"
		icmp type echo-request counter packets 0 bytes 0 accept comment "!fw4: Allow-Ping"
		meta nfproto ipv4 meta l4proto igmp counter packets 0 bytes 0 accept comment "!fw4: Allow-IGMP"
		meta nfproto ipv6 udp dport 546 counter packets 0 bytes 0 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 packets 0 bytes 0 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 packets 0 bytes 0 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 packets 0 bytes 0 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 packets 0 bytes 0 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 packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Forward"
		meta l4proto esp counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow-IPSec-ESP"
		udp dport 500 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow-ISAKMP"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] tcp dport [redacted] counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow i2p inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] udp dport [redacted] counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow i2p inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] tcp dport [redacted] counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow qbittorrent inbound"
		ip6 daddr & ::ffff:ffff:ffff:ffff == ::[redacted] udp dport [redacted] counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow qbittorrent inbound"
		jump reject_to_wan
	}

	chain accept_to_wan {
		meta nfproto ipv4 oifname { "eth1", "pppoe-wan" } ct state invalid counter packets 0 bytes 0 drop comment "!fw4: Prevent NAT leakage"
		oifname { "eth1", "pppoe-wan" } counter packets 402 bytes 52416 accept comment "!fw4: accept wan IPv4/IPv6 traffic"
	}

	chain reject_from_wan {
		iifname { "eth1", "pppoe-wan" } counter packets 3 bytes 468 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain reject_to_wan {
		oifname { "eth1", "pppoe-wan" } counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain dstnat {
		type nat hook prerouting priority dstnat; policy accept;
		jump upnp_prerouting comment "Hook into miniupnpd prerouting chain"
	}

	chain srcnat {
		type nat hook postrouting priority srcnat; policy accept;
		oifname { "eth1", "pppoe-wan" } jump srcnat_wan comment "!fw4: Handle wan IPv4/IPv6 srcnat traffic"
		jump upnp_postrouting comment "Hook into miniupnpd postrouting chain"
	}

	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 { "eth1", "pppoe-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 { "eth1", "pppoe-wan" } tcp flags & (fin | syn | rst) == syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 ingress MTU fixing"
	}

	chain upnp_forward {
	}

	chain upnp_prerouting {
	}

	chain upnp_postrouting {
	}
}

Running command nft list ruleset after the nft file moved back gave output compared to previous command:

diff --git 1/fw4-output-0.txt 2/fw4-output-1.txt
index bf2bb97..508eb54 100644
--- 1/fw4-output-0.txt
+++ 2/fw4-output-1.txt
@@ -58,11 +58,11 @@ table inet fw4 {
 	}
 
 	chain accept_from_lan {
-		iifname "br-lan" counter packets 6 bytes 512 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
+		iifname "br-lan" counter packets 7 bytes 552 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
 	}
 
 	chain accept_to_lan {
-		oifname "br-lan" counter packets 3 bytes 264 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
+		oifname "br-lan" counter packets 1 bytes 72 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
 	}
 
 	chain input_wan {
@@ -94,11 +94,11 @@ table inet fw4 {
 
 	chain accept_to_wan {
 		meta nfproto ipv4 oifname { "eth1", "pppoe-wan" } ct state invalid counter packets 0 bytes 0 drop comment "!fw4: Prevent NAT leakage"
-		oifname { "eth1", "pppoe-wan" } counter packets 402 bytes 52416 accept comment "!fw4: accept wan IPv4/IPv6 traffic"
+		oifname { "eth1", "pppoe-wan" } counter packets 123 bytes 12379 accept comment "!fw4: accept wan IPv4/IPv6 traffic"
 	}
 
 	chain reject_from_wan {
-		iifname { "eth1", "pppoe-wan" } counter packets 3 bytes 468 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
+		iifname { "eth1", "pppoe-wan" } counter packets 1 bytes 311 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
 	}
 
 	chain reject_to_wan {
@@ -130,6 +130,8 @@ table inet fw4 {
 
 	chain mangle_prerouting {
 		type filter hook prerouting priority mangle; policy accept;
+		ip saddr 192.168.1.123 meta mark set 0x00000001
+		ip6 saddr fdcf:4d5e:8ba6::123 meta mark set 0x00000001
 	}
 
 	chain mangle_postrouting {

Note: No public IP addresses found in nft output.

Have my word on it - it is capable of barfing out all correct lines except one with error....

Where do those meta-mark lines come in, bc the upnp are included right after hook definition or after rest of rules in hook?

Yes it is, considering that if you try to re-add an existing “hook-less” chain manually with a “hook”, you get an expected error.

root@router:~# nft -c add chain 'inet fw4 output_wan { type filter hook output priority filter; policy accept; }'
Error: Chain "output_wan" already exists in table inet 'fw4' with different declaration
add chain inet fw4 output_wan { type filter hook output priority filter; policy accept; }
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It looks like my nft file came earlier than fw4's filter rules, but why? wouldn't it makes sense if my nft rules came after fw4's? Or is it somewhere some commit in the OpenWrt code made such decision?

Your rules in nftables.d come first. They must have exact hook or different name than later rules. Make it priority filter - 1 and its good to go.

Also you cannot replace hook with different one, like be careful when inserting rule in default in/out/forward chains that change hook from configuration.

You kind of perfectly see where they are included in fw4 print.

2 Likes

Prcisely initially intended as this.

1 Like

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