DNS highjacking with fw4 and nftables in 22.03.0

Can you please post the /etc/config/firewall file leading to this error so we can fix this issue? The firewall should not crash like that.

Apart from that, the above error can be mitigated by correcting your currently invalid configuration.

Edit: I am able to reproduce the crash, investigating it now.

Edit 2:

To correct your configuration, run the following commands:

uci set firewall.doh=ipset
uci set firewall.doh.name=doh
uci set firewall.doh.family=ipv4
uci set firewall.doh.match=ip

uci set firewall.doh6=ipset
uci set firewall.doh6.name=doh6
uci set firewall.doh6.family=ipv6
uci set firewall.doh6.match=ip

uci commit firewall
fw4 restart
1 Like

Thx for the help.

Now this Is the situation

BusyBox v1.35.0 (2022-09-03 02:55:34 UTC) built-in shell (ash)
  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt 22.03.0, r19685-512e76967f
 -----------------------------------------------------
root@OpenWrt:~# uci set firewall.doh=ipset
uci set firewall.doh.name=doh
uci set firewall.doh.family=ipv4
uci set firewall.doh.match=ip
uci set firewall.doh6=ipset
uci set firewall.doh6.name=doh6
uci set firewall.doh6.family=ipv6
uci set firewall.doh6.match=ip
uci commit firewall
fw4 restartroot@OpenWrt:~# uci set firewall.doh.name=doh
root@OpenWrt:~# uci set firewall.doh.family=ipv4
root@OpenWrt:~# uci set firewall.doh.match=ip
root@OpenWrt:~#
root@OpenWrt:~# uci set firewall.doh6=ipset
root@OpenWrt:~# uci set firewall.doh6.name=doh6
root@OpenWrt:~# uci set firewall.doh6.family=ipv6
root@OpenWrt:~# uci set firewall.doh6.match=ip
root@OpenWrt:~#
root@OpenWrt:~# uci commit firewall
root@OpenWrt:~# fw4 restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
root@OpenWrt:~# for IPV in 4 6
> do
> uci -q delete firewall.doh${IPV%4}_fwd
> uci set firewall.doh${IPV%4}_fwd="rule"
> uci set firewall.doh${IPV%4}_fwd.name="Deny-DoH"
> uci set firewall.doh${IPV%4}_fwd.src="lan"
> uci set firewall.doh${IPV%4}_fwd.dest="wan"
> uci set firewall.doh${IPV%4}_fwd.dest_port="443"
> uci set firewall.doh${IPV%4}_fwd.proto="tcp udp"
> uci set firewall.doh${IPV%4}_fwd.family="ipv${IPV}"
> uci set firewall.doh${IPV%4}_fwd.ipset="doh${IPV%4} dest"
> uci set firewall.doh${IPV%4}_fwd.target="REJECT"
> done
uci commit firewall
/etc/init.d/firewall restartroot@OpenWrt:~# uci commit firewall
root@OpenWrt:~# /etc/init.d/firewall restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
root@OpenWrt:~# mkdir -p /etc/hotplug.d/online
root@OpenWrt:~# cat << "EOF" > /etc/hotplug.d/online/60-ipset-doh
> if [ ! -e /var/lock/ipset-doh ] \
> && lock -n /var/lock/ipset-doh
> then
> uclient-fetch -O - "https://raw.githubusercontent.com/\
> dibdot/DoH-IP-blocklists/master/doh-domains.txt" \
> | uci -q batch << EOI
> delete dhcp.doh.domain
> $(sed -e "s/^.*$/\
> del_list dhcp.doh.domain='\0'\n\
> add_list dhcp.doh.domain='\0'/")
> commit dhcp
> EOI
> lock -u /var/lock/ipset-doh
> fi
> EOF
root@OpenWrt:~# cat << "EOF" >> /etc/sysupgrade.conf
> /etc/hotplug.d/online/60-ipset-doh
> EOF
root@OpenWrt:~# . /etc/hotplug.d/online/60-ipset-doh
root@OpenWrt:~# ipset setup
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
root@OpenWrt:~# etc/init.d/firewall restart
-ash: etc/init.d/firewall: not found
root@OpenWrt:~# uci -q delete firewall.dot_fwd
uci set firewall.dot_fwd="ruroot@OpenWrt:~# uci set firewall.dot_fwd="rule"
ci set firewall.dot_fwd.namroot@OpenWrt:~# uci set firewall.dot_fwd.name="Deny-DoT"
uci set firewall.dot_fwd.src="lan"
uci set firewaroot@OpenWrt:~# uci set firewall.dot_fwd.src="lan"
wd.dest="wan"
uci set firewallroot@OpenWrt:~# uci set firewall.dot_fwd.dest="wan"
.dest_port="853"
uci set firroot@OpenWrt:~# uci set firewall.dot_fwd.dest_port="853"
ll.dot_fwd.proot@OpenWrt:~# uci set firewall.dot_fwd.proto="tcp udp"
uci set firewroot@OpenWrt:~# uci set firewall.dot_fwd.target="REJECT"
uci commit fireroot@OpenWrt:~# uci commit firewall
/etc/init.d/firewall restartroot@OpenWrt:~# /etc/init.d/firewall restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible
root@OpenWrt:~# uci set firewall.dns_int.name="Redirect-DNS"
uci set firewall.dns_int.srcuci: Invalid argument
_iroot@OpenWrt:~# uci set firewall.dns_int.src_ip="!192.168.1.4"
uci set firewall.dns_inuci: Invalid argument
t.root@OpenWrt:~# uci set firewall.dns_int.dest_ip="192.168.1.4"
uci -q delete fuci: Invalid argument
irewall.dns_masq
uci set firewaroot@OpenWrt:~# uci -q delete firewall.dns_masq
l.dns_masq="nat"
uci set froot@OpenWrt:~# uci set firewall.dns_masq="nat"
ewall.dns_masq.name="Masquroot@OpenWrt:~# uci set firewall.dns_masq.name="Masquerade-DNS"
uci set firewall.dns_masq.src="lan"
uci set firewallroot@OpenWrt:~# uci set firewall.dns_masq.src="lan"
s_masq.dest_ip="192.168.root@OpenWrt:~# uci set firewall.dns_masq.dest_ip="192.168.1.4"
uci set firewall.dns_masq.dest_port="53"
uci set froot@OpenWrt:~# uci set firewall.dns_masq.dest_port="53"
irewall.dns_masq.proto="troot@OpenWrt:~# uci set firewall.dns_masq.proto="tcp udp"
uci set firewall.dns_masq.tarroot@OpenWrt:~# uci set firewall.dns_masq.target="MASQUERADE"
uci commit firewall
/etc/init.d/firewall restartroot@OpenWrt:~# uci commit firewall
root@OpenWrt:~# /etc/init.d/firewall restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible

My locale dns server Is the same up of the router but Is adguardhome installed.
I see a lot of invalidi argument and It doenst work unfortunatly

not sure from where and how you copied these lines to shell but it is definitely wrong for many reasons.

e.g.

root@OpenWrt:~# etc/init.d/firewall restart
-ash: etc/init.d/firewall: not found

should be 
root@OpenWrt:~# /etc/init.d/firewall restart

the rest is total mess. it looks you just copy-pasted somehow without line end.

root@OpenWrt:~# uci -q delete firewall.dot_fwd
uci set firewall.dot_fwd="ruroot@OpenWrt:~# uci set firewall.dot_fwd="rule"
ci set firewall.dot_fwd.namroot@OpenWrt:~# uci set firewall.dot_fwd.name="Deny-DoT"

should be:
root@OpenWrt:~# uci -q delete firewall.dot_fwd [ENTER]
root@OpenWrt:~# uci set firewall.dot_fwd="rule" [ENTER]
root@OpenWrt:~# uci set firewall.dot_fwd.name="Deny-DoT" [ENTER]

copy commands one by one instead of one big text. it can work though but requires proper line end characters, but it does not look like in your case. might be terminal settings in your ssh client, or silent formatting during copy-paste.

also check the codes you try to apply whether they are nftables compatible or not. owrt 22.03 is using nftables instead of iptables, and nftables has native set support does not require external ipset tool. also keep in mind adguard supports ipsets only, it is not nftables compatible (yet). so you may need replace ipset add commands to nft add element etc

1 Like

Thx for your patience and help. I managed to enter correctly all the lines and this is the result in the firewall config

config defaults
	option input 'ACCEPT'
	option output 'ACCEPT'
	option synflood_protect '1'
	option forward 'ACCEPT'

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

config zone
	option name 'wan'
	option output 'ACCEPT'
	option masq '1'
	option mtu_fix '1'
	option input 'ACCEPT'
	option forward 'ACCEPT'

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 src_ip 'fc00::/6'
	option dest_ip 'fc00::/6'
	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 'Support-UDP-Traceroute'
	option src 'wan'
	option dest_port '33434:33689'
	option proto 'udp'
	option family 'ipv4'
	option target 'REJECT'
	option enabled '0'

config include
	option path '/etc/firewall.user'

config rule
	option name 'transmission'
	option src 'lan'
	option src_port '9091'
	option dest 'lan'
	option dest_port '9091'
	option target 'ACCEPT'

config ipset 'doh'
	option name 'doh'
	option family 'ipv4'
	option match 'net'

config ipset 'doh6'
	option name 'doh6'
	option family 'ipv6'
	option match 'net'

config redirect 'dns_int'
	option src 'lan'
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option name 'Redirect-DNS'
	option src_ip '!192.168.1.4'
	option dest_ip '192.168.1.4'
	option src_mac '!00:11:22:33:44:55'

config nat 'dns_masq'
	option name 'Masquerade-DNS'
	option src 'lan'
	option dest_ip '192.168.1.4'
	option dest_port '53'
	option proto 'tcp udp'
	option target 'MASQUERADE'

config rule 'doh_fwd'
	option name 'Deny-DoH'
	option src 'lan'
	option dest 'wan'
	option dest_port '443'
	option proto 'tcp udp'
	option family 'ipv4'
	option ipset 'doh dest'
	option target 'REJECT'

config rule 'doh6_fwd'
	option name 'Deny-DoH'
	option src 'lan'
	option dest 'wan'
	option dest_port '443'
	option proto 'tcp udp'
	option family 'ipv6'
	option ipset 'doh6 dest'
	option target 'REJECT'

config rule 'dot_fwd'
	option name 'Deny-DoT'
	option src 'lan'
	option dest 'wan'
	option dest_port '853'
	option proto 'tcp udp'
	option target 'REJECT'

but its now working at all. Unfortunatly i dont have enough knowledge to understand the ipset problem,

I dont know if these warnings are ok

root@OpenWrt:~# /etc/init.d/firewall restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section dns_int (Redirect-DNS) does not specify a destination, assuming 'lan'
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible

i dont know how to continue at this point, my main goal is to direct all my devices to my local dns server (adguard) and follow the dns rewrite rules.
However it seem to works , but at some point i made an.error becouse if One router in particular is online, It becomes the target of the rewrite rule. If It Is offline the rewrite works perfectly.Thank you very much for your help.

1. Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section

This is just for you info as corresponding rule is:

config rule
	option name 'Support-UDP-Traceroute'
	[..]
	option enabled '0' <-- disabled

2. Section dns_int (Redirect-DNS) does not specify a destination, assuming 'lan'

This is ok, better would be to explicitly define destination zone though.
config redirect 'dns_int'
	option src 'lan'
# option dest 'lan' <-- not needed but makes more readable and would remove the warning
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option name 'Redirect-DNS'
	option src_ip '!192.168.1.4'
	option dest_ip '192.168.1.4'
	option src_mac '!00:11:22:33:44:55'

3. 
Section @include[0] is not marked as compatible with fw4, ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible

you have this include rule
config include
	option path '/etc/firewall.user'
which may or may not remain from pre-22.03 config. 
in 22.03 fw4 is the firewall which by default does not use legacy /etc/firewall.user. 
if you want custom rules you can still use but 
must define rules in nftables (which is the firewall app underneth fw4) style and 
mark explicitly this include file is fw4 compatible. 
so it is,again, just a warning that in this format /etc/firewall.user is not included.

Now your other problem:

config redirect 'dns_int'
	option src 'lan'
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option name 'Redirect-DNS'
	option src_ip '!192.168.1.4'
	option dest_ip '192.168.1.4'
	option src_mac '!00:11:22:33:44:55' 

this rule will only applied if source is not 192.168.1.4 and source MAC address is not 00:11:22:33:44:55. you say there is different behavior if one router is online or offline. what are your routers ip and mac addresses?

by the way can you see your doh/doh6 sets are filled with data? nft list ruleset could verify this.

1 Like

thank you very much for your help

root@OpenWrt:~# nft list ruleset
table ip nat {
        chain dnshijack {
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_DNAT
                counter packets 0 bytes 0 # xt_DNAT
        }

        chain PREROUTING {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "br*" meta l4proto udp ip saddr != 192.168.1.4 # xt_udp counter packets 3312 bytes 229741 # xt_DNAT
                iifname "br*" meta l4proto tcp ip saddr != 192.168.1.4 # xt_tcp counter packets 0 bytes 0 # xt_DNAT
                ip daddr 8.8.4.4 counter packets 51 bytes 3216 # xt_DNAT
                ip daddr 8.8.8.8 counter packets 8356 bytes 700803 # xt_DNAT
                iifname "br0" meta l4proto udp ip saddr != 192.168.1.1 ip daddr != 192.168.1.1 # xt_udp counter packets 0 bytes 0 # xt_DNAT
                iifname "br0" meta l4proto tcp ip saddr != 192.168.1.1 ip daddr != 192.168.1.1 # xt_tcp counter packets 0 bytes 0 # xt_DNAT
        }

        chain POSTROUTING {
                type nat hook postrouting priority srcnat; policy accept;
                counter packets 22580 bytes 1703755 # xt_MASQUERADE
        }
}
table ip6 nat {
        chain dnshijack {
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_DNAT
                counter packets 0 bytes 0 # xt_DNAT
        }
}
table ip filter {
        chain FORWARD {
                type filter hook forward priority filter; policy accept;
                ip daddr 8.8.4.4 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.8.8 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.4.4 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.8.8 counter packets 0 bytes 0 # xt_REJECT
        }
}
table inet fw4 {
        set doh {
                type ipv4_addr
                flags interval
                auto-merge
        }

        set doh6 {
                type ipv6_addr
                flags interval
                auto-merge
        }

        chain input {
                type filter hook input priority filter; policy accept;
                iifname "lo" accept comment "!fw4: Accept traffic from loopback"
                ct state established,related accept comment "!fw4: Allow inbound established and related flows"
                tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets"
                iifname "br-lan" jump input_lan comment "!fw4: Handle lan IPv4/IPv6 input traffic"
        }

        chain forward {
                type filter hook forward priority filter; policy accept;
                ct state established,related accept comment "!fw4: Allow forwarded established and related flows"
                iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
        }

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

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

        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 {
                ct status dnat accept comment "!fw4: Accept port redirections"
                jump accept_from_lan
        }

        chain output_lan {
                jump accept_to_lan
        }

        chain forward_lan {
                tcp dport 853 counter packets 136898032 bytes 8213884412 jump handle_reject comment "!fw4: ubus:https-dns-proxy[instance1] rule 1"
                udp dport 853 counter packets 0 bytes 0 jump handle_reject comment "!fw4: ubus:https-dns-proxy[instance1] rule 1"
                tcp sport 9091 tcp dport 9091 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: transmission"
                udp sport 9091 udp dport 9091 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: transmission"
                tcp dport 443 ip daddr @doh counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                udp dport 443 ip daddr @doh counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                tcp dport 443 ip6 daddr @doh6 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                udp dport 443 ip6 daddr @doh6 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                tcp dport 853 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoT"
                udp dport 853 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoT"
                jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
                ct status dnat accept comment "!fw4: Accept port forwards"
                jump accept_to_lan
        }

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

        chain accept_to_lan {
                oifname "br-lan" counter packets 167759 bytes 20012209 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"
                ip6 saddr fc00::/6 ip6 daddr fc00::/6 udp dport 546 counter packets 0 bytes 0 accept comment "!fw4: Allow-DHCPv6"
                ip6 saddr fe80::/10 icmpv6 type . icmpv6 code { mld-listener-query . no-route, mld-listener-report . no-route, mld-listener-done . no-route, mld2-listener-report . no-route } 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 counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Input"
                icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, nd-neighbor-solicit . no-route, nd-neighbor-advert . no-route, parameter-problem . admin-prohibited } limit rate 1000/second counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Input"
                jump accept_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 counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Forward"
                icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, parameter-problem . admin-prohibited } limit rate 1000/second 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"
                jump accept_to_wan
        }

        chain accept_from_wan {
        }

        chain accept_to_wan {
        }

        chain reject_to_wan {
        }

        chain dstnat {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "br-lan" jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
        }

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

        chain dstnat_lan {
                meta nfproto ipv4 tcp dport 53 counter packets 27 bytes 1404 redirect to :53 comment "!fw4: ubus:https-dns-proxy[instance1] redirect 0"
                meta nfproto ipv4 udp dport 53 counter packets 43076 bytes 2961467 redirect to :53 comment "!fw4: ubus:https-dns-proxy[instance1] redirect 0"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 tcp dport 53 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr != 192.168.1.4 tcp dport 53 ether saddr != 00:11:22:33:44:55 counter packets 0 bytes 0 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 udp dport 53 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr != 192.168.1.4 udp dport 53 ether saddr != 00:11:22:33:44:55 counter packets 0 bytes 0 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS"
        }

        chain srcnat_lan {
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 tcp dport 53 snat ip to 192.168.1.4 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 udp dport 53 snat ip to 192.168.1.4 comment "!fw4: Redirect-DNS (reflection)"
                ip daddr 192.168.1.4 tcp dport 53 masquerade comment "!fw4: Masquerade-DNS"
                ip daddr 192.168.1.4 udp dport 53 masquerade comment "!fw4: Masquerade-DNS"
                meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 lan 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;
        }

        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;
        }
}

my network is:

  • ISP router, used only as gateway 192.168.1.1
  • main router, xiaomi mi 4g, 192.168.1.4 openwrt 22.03
  • DUMB AP router, xiaomi mi 4a, 192.168.1.3 openwrt 21.0
  • DUMB ap router, xiaomi ax 3600, 192.168.1.2 openwrt 22.03

this behavior only happens on my pixel 7 pro and not on my other devices. If the xiaomi ax3600 router is online the dns rewrite is directed to 192.168.1.2 instead of 192.168.1.29 which is the ip of my smartphone, all the other devices at the moment do not seem affected by this behavior.
Now to make everything work I momentarily disconnected the xiaomi ax3600 device.

Thank you for the explanation, i learned a lot of new things.

I dont know if the list of ruleset is affected by several attempts made to get the same result of dns hijacking with other guides

based on this a) nft sets are created which is good; and b) they are not filled with any IP address which is not so good. i guess you followed this https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns and then https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns#dns_over_https . which has been a solid solution for fw3(iptables)+ipset world. but as said earlier it is not working with nftables natively.

you need some tiny modifications.

  1. keep /etc/horplug.d/iface/90-online it is responsible to trigger online plugins if your wan become active.
  2. keep /etc/horplug.d/online/60-ipset-doh it is responsible to add known public DoH DNS servers to dhcp.doh.domain list.
  3. create/modify /etc/hotplug.d/online/90-DoH to use nft add element instead of ipset add.
    a very rough plugin skeleton may look like this (note: this is a raw skeleton feel free to add as many whistles as you want, e.g. logging, error check etc)
lock -n /var/lock/doh.lock 
for d in $( uci show dhcp.doh.domain | sed -e 's|^.*=||' -e "s|'||g")
do
        for ip in $( resolveip $d )
        do
                [ $( expr index "$ip" '.' ) -gt 0 ] && nft add element inet fw4 doh { $ip } || nft add element inet fw4 doh6 { $ip }
        done
done
lock -u /var/lock/doh.lock oH
  1. this https://openwrt.org/docs/guide-user/advanced/ipset_extras is not needed in fw4 environment, just make sure /etc/confg/firewall includes the set configurations (doh/doh6)

then the process will be:

  1. fw4 creates doh/doh6 sets empty
  2. when wan becomes active (up) then /etc/hotplug.d/iface/90-online calls plugins from /etc/hotplug.d/online
  3. first 60-ipset-doh will add known DoH servers list
  4. then 90-doh will resolve corresponding ip addresses and add to doh/doh6
  5. then in any firewall rule you can reference to doh/doh6
1 Like

your dumb ap's are really dumb? i mean redirect rule should be on your main router xiaomi 4g only, i dont see how one or other dump router could impact this if they are really dumb. meaning there is minimal configuration (i.e. the minimum required to run and vlan related maybe) exists on them. but no dhcp, dns and firewall services are supposed to be active on them.

1 Like

tomorrow i will check, but i followed the guide to make them dumb, however i can reset the xiaomi and try to reconfig it from scratch.

So I went to the etc/hotplug.d/online folder and there was no file called 90-doh, I created it and copied that "lock..." text, I think I followed everything you indicated, did i miss something? Do I need to do anything to make this configactive? Or is it enough to create that file?

Thanks again for the help

you followed this guide https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns#dns_over_https , right?

it says:

Filter DoH traffic with firewall and IP sets forcing LAN clients to switch to plain DNS. Set up IP set extras and Hotplug extras to automatically populate IP sets.

then bunch of commands. those commands will create /etc/hotplug.d/online/60-ipset-doh among other things but rely on the other two guides.

"hotplug extras" take care of creating the "online" hotplug dir and triggering mechanism, i.e. when wan turns up the plugin created iface/90-online will trigger the plugins under online dir. e.g. the online/60-ipset-doh.

but online/60-ipset-doh is just the first part of the story as it is grabbing the DoH domain names only. you'll need something which resolves the ips for those domains and put them into doh/doh6 ipset or nft set (depending on your fw version fw3 or fw4). note: obviously you can put everything into one single plugin, it is up to you.

Hi grrr2 & morpheus88!

Firstly i want to thank you, morpheus88 for posting on multiple threads and providing a link to new threads! i had the same issue as you, about the

ipset = filter(this.state.ipsets, s => (s.name == rule.ipset.name))[0];`
  Near here ----------------------------------------------------------------------^

and that's how i found you and please know that i am following your threads closely!

And thank you grrr2 for helping out on this issue! Please know that you are now helping at least 1 other person, and many more to come in the future! :slight_smile:
I am a big noob too hehe, but i have a slightyl different configuration as morpheus88; i have a raspberry pi running pihole connected to my OpenWRT.

i am pretty sure i am doing exactly as morpheus88, but i did not receive these errors:

root@OpenWrt:~# /etc/init.d/firewall restart
Section @rule[9] (Support-UDP-Traceroute) is disabled, ignoring section
Section @include[0] is not marked as compatible with fw4, .ignoring section
Section @include[0] requires 'option fw4_compatible 1' to be considered compatible

just this one alone (which i corrected according to your suggestion above):

root@OpenWrt:~# /etc/init.d/firewall restart
Section dns_int (Redirect-DNS) does not specify a destination, assuming 'lan'

also, i have only fewer entries on nft list ruleset

root@OpenWrt:~# nft list ruleset
table inet fw4 {

   set doh {
           type ipv4_addr
   }

   set doh6 {
           type ipv6_addr
   }

(continues with the other rules below)

And i noticed you mentioned ipset is not needed in OpenWRT 22.X.X, but i thought the guide missed it so i did a opkg install ipset, should i delete it?

Anyways, sorry for the long post... i will just pay attention to both of your discussions for now, cause i know it can be confusing to help out 2 person with different configurations simultaneously (let me know otherwise :wink: ). Just know that you, my friend, are the only person that seem to know enough on this issue to help!

PS: I am following the exact same guide as morpheus88 "https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns#dns_redirection" &&& my OpenWRT version is newer: 22.03.2 :stuck_out_tongue: hopefully that don't give me more problems hehe.

Really big thanks to the both of you!

yes i followed that guide. I dont know if its relevant but on my main router i dont have any wan interface, only a lan interface.
However i dont think to have enough knowledge to full understand what you are saying. This is my nft list ruleset now, i dont see any relevant difference.

root@OpenWrt:~#  nft list ruleset
table ip nat {
        chain dnshijack {
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_DNAT
                counter packets 0 bytes 0 # xt_DNAT
        }

        chain PREROUTING {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "br*" meta l4proto udp ip saddr != 192.168.1.4 # xt_udp counter packets 3315 bytes 229974 # xt_DNAT
                iifname "br*" meta l4proto tcp ip saddr != 192.168.1.4 # xt_tcp counter packets 0 bytes 0 # xt_DNAT
                ip daddr 8.8.4.4 counter packets 68 bytes 4292 # xt_DNAT
                ip daddr 8.8.8.8 counter packets 11198 bytes 939103 # xt_DNAT
                iifname "br0" meta l4proto udp ip saddr != 192.168.1.1 ip daddr != 192.168.1.1 # xt_udp counter packets 0 bytes 0 # xt_DNAT
                iifname "br0" meta l4proto tcp ip saddr != 192.168.1.1 ip daddr != 192.168.1.1 # xt_tcp counter packets 0 bytes 0 # xt_DNAT
        }

        chain POSTROUTING {
                type nat hook postrouting priority srcnat; policy accept;
                counter packets 28430 bytes 2052263 # xt_MASQUERADE
        }
}
table ip6 nat {
        chain dnshijack {
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_LOG
                counter packets 0 bytes 0 # xt_DNAT
                counter packets 0 bytes 0 # xt_DNAT
        }
}
table ip filter {
        chain FORWARD {
                type filter hook forward priority filter; policy accept;
                ip daddr 8.8.4.4 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.8.8 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.4.4 counter packets 0 bytes 0 # xt_REJECT
                ip daddr 8.8.8.8 counter packets 0 bytes 0 # xt_REJECT
        }
}
table inet fw4 {
        set doh {
                type ipv4_addr
                flags interval
                auto-merge
        }

        set doh6 {
                type ipv6_addr
                flags interval
                auto-merge
        }

        chain input {
                type filter hook input priority filter; policy accept;
                iifname "lo" accept comment "!fw4: Accept traffic from loopback"
                ct state established,related accept comment "!fw4: Allow inbound established and related flows"
                tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets"
                iifname "br-lan" jump input_lan comment "!fw4: Handle lan IPv4/IPv6 input traffic"
        }

        chain forward {
                type filter hook forward priority filter; policy accept;
                ct state established,related accept comment "!fw4: Allow forwarded established and related flows"
                iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
        }

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

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

        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 {
                ct status dnat accept comment "!fw4: Accept port redirections"
                jump accept_from_lan
        }

        chain output_lan {
                jump accept_to_lan
        }

        chain forward_lan {
                tcp dport 853 counter packets 144048343 bytes 8642903296 jump handle_reject comment "!fw4: ubus:https-dns-proxy[instance1] rule 1"
                udp dport 853 counter packets 0 bytes 0 jump handle_reject comment "!fw4: ubus:https-dns-proxy[instance1] rule 1"
                tcp sport 9091 tcp dport 9091 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: transmission"
                udp sport 9091 udp dport 9091 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: transmission"
                tcp dport 443 ip daddr @doh counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                udp dport 443 ip daddr @doh counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                tcp dport 443 ip6 daddr @doh6 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                udp dport 443 ip6 daddr @doh6 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoH"
                tcp dport 853 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoT"
                udp dport 853 counter packets 0 bytes 0 jump reject_to_wan comment "!fw4: Deny-DoT"
                jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
                ct status dnat accept comment "!fw4: Accept port forwards"
                jump accept_to_lan
        }

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

        chain accept_to_lan {
                oifname "br-lan" counter packets 194796 bytes 29221553 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"
                ip6 saddr fc00::/6 ip6 daddr fc00::/6 udp dport 546 counter packets 0 bytes 0 accept comment "!fw4: Allow-DHCPv6"
                ip6 saddr fe80::/10 icmpv6 type . icmpv6 code { mld-listener-query . no-route, mld-listener-report . no-route, mld-listener-done . no-route, mld2-listener-report . no-route } 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 counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Input"
                icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, nd-neighbor-solicit . no-route, nd-neighbor-advert . no-route, parameter-problem . admin-prohibited } limit rate 1000/second counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Input"
                jump accept_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 counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Forward"
                icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, parameter-problem . admin-prohibited } limit rate 1000/second 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"
                jump accept_to_wan
        }

        chain accept_from_wan {
        }

        chain accept_to_wan {
        }

        chain reject_to_wan {
        }

        chain dstnat {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "br-lan" jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
        }

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

        chain dstnat_lan {
                meta nfproto ipv4 tcp dport 53 counter packets 49 bytes 2548 redirect to :53 comment "!fw4: ubus:https-dns-proxy[instance1] redirect 0"
                meta nfproto ipv4 udp dport 53 counter packets 58193 bytes 3983255 redirect to :53 comment "!fw4: ubus:https-dns-proxy[instance1] redirect 0"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 tcp dport 53 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr != 192.168.1.4 tcp dport 53 ether saddr != 00:11:22:33:44:55 counter packets 0 bytes 0 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 udp dport 53 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr != 192.168.1.4 udp dport 53 ether saddr != 00:11:22:33:44:55 counter packets 0 bytes 0 dnat ip to 192.168.1.4:53 comment "!fw4: Redirect-DNS"
        }

        chain srcnat_lan {
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 tcp dport 53 snat ip to 192.168.1.4 comment "!fw4: Redirect-DNS (reflection)"
                ip saddr 192.168.1.0/24 ip daddr 192.168.1.4 udp dport 53 snat ip to 192.168.1.4 comment "!fw4: Redirect-DNS (reflection)"
                ip daddr 192.168.1.4 tcp dport 53 masquerade comment "!fw4: Masquerade-DNS"
                ip daddr 192.168.1.4 udp dport 53 masquerade comment "!fw4: Masquerade-DNS"
                meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 lan 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;
        }

        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;
        }
}

thx again

you were right, now it works with the xiaomi ax3600 router online

some background first:

by default owrt is offering (DHCP and) DNS service for lan clients. DNS service covers for example knowledge about your clients (their name and ip address mapping), or which upstream DNS server to use in case owrt DNS cannot resolve a name (i.e. how to find public domain name ip addresses), or filter DNS.

now, let's focus on latter part, i.e. how to define which upstream to use.

the problem is that it is offer only, a client can decide not to use owrt's dns server (dnsmasq) which is set to use one particular upstream server (in one or other way, that's also a long story how many different way it can be set). simply setting the DNS server config on the client and it will go out straight to that upstream DNS server. so if you set DNS filtering on owrt it will be bypassed.

thus the idea which is called DNS hijacking: as DNS traffic is well known, if network admin redirects any attempt from clients on lan accessing the well-known dns port 53 in wan direction to the locally controlled/preferred dns server (=owrt dnsmasq), clients will not able to bypass the preferred dns filtering rules for example.

that was easy to do. but.

lots of clients nowadays (mobile phones, tv boxes, iot devices and web browsers ( ! ) too) using hardwired config pointing to whatever upstream DNS server not under your control/non-configurable/non-deactivable (if such word exists) way and with encrypted dns protocol such as DNS-over-HTTPS which is using port 443 it became impossible to use redirection technique. because port 443 for HTTPS is a legit traffic, you don't want to redirect normal HTTPS traffic to your dns server instead of the corresponding web server.

and here comes the second idea to mitigate it.

if these clients are using some known public DoH upstream server, because as above we cannot redirect or filter out based on port 443, let's reject connection to those server based on their ip addresses (as firewalls will not able to filter based on domain name) so they fallback to the offered dns server (which is our preferred server)!

and here we are: ip/nft set is a placeholder for ip addresses, as your nft ruleset shows doh/doh6 sets are created. but empty! something needs to fill it with ip addresses used by the public DoH servers.

and that when the 3rd idea came:

using owrt hotplug framework, let's hook plugins to the event when wan interface become active. that is done by the online hotplug you read in the wiki. it has two parts: one is creating the hook, the other is creating the plugins which will a) download the list of known DoH servers b) resolve their ip addresses and add to set.

this is where the wiki guide is not really up-to-date: till v21 ipset was used, the example codes are based on that. since v22 fw4 firewall (based on nftables) using it's own implementation called nft set. so the wiki example code will not work.

so in your case you need to solve two things:

  • as you say your main router is not your gateway to internet and or not using wan interface. so trigger events when wan is up will not work for you. you need some other mechanism to download&resolve&add to set.
  • and obviously you need to adapt the example code to use nft set syntax instead of ipset.

so you are almost there :slight_smile:

Thx for the explanation, now the Logic Is more clear however i dont know what to do.

Is this thread dead? Or should we just wait for the OpenWrt folks to update that documentation? :confused:

You can feel free to update the Wiki.

i certainly do not have the knowledge to do that. Can i submit a request somewhere for others to help do that?

You’ve answered your question yourself. Wiki updates is a volunteer project.

1 Like

Sir or ma'am, would you kindly update it please?