Requesting Assist to enforce DNS to AdguardHome/Pi-Hole

Hello all,

Again I'm requesting your assistance to help me to configure the new firewall and hijack the dns for my android and google devices that have embedded the dns into their hardware to go into my device with ADH/Pi-hole with unbound.

I followed this guide for DNS hijacking but somehow after the Intercep DNS section for the firewall I don't lost connection but unable to surf into the web so my guess is i'm blocking my self from the dns server.

Also I read that this new version of OpenWrt 22+ uses NFtables/Firewall4 instead IpTables/Firewall3 and maybe that is the problem.

My setup.

OpenWrt Router -- RasberryPi (dns & dhcp) ADH/Pi-Hole with unbound -- LAN devices

My DHCP file (although the dhcp is running on the ADH/Pi-Hole)

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option localservice '1'
        option ednspacket_max '1232'

config dhcp 'lan'
        option interface 'lan'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'
        option limit '50'
        option leasetime '8h'
        option start '200'
        list dhcp_option '6,10.105.10.2,10.105.10.2'
        option ignore '1'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

and my firewall

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

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

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

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 redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'VPN'
        list proto 'udp'
        option src 'wan'
        option src_dport '51820'
        option dest_ip '10.105.10.2'
        option dest_port '51820'

my network file

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 packet_steering '1'
        option ula_prefix 'fdd0:378d:6f27::/48'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth1'
        list ports 'eth2'
        list ports 'eth3'
        list ports 'eth4'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option netmask '255.255.255.0'
        option ipaddr '10.105.10.1'

config interface 'wan'
        option device 'eth0'
        option proto 'pppoe'
        option username 'redacted'
        option password 'redacted'
        option ipv6 '0'
        option peerdns '0'
        option delegate '0'
        option mtu '1492'
        list dns '1.1.1.1'
        list dns '1.0.0.1'

What I want to accomplish is to make sure all the dns traffic from the lan goes to the ADH/Pi-hole device so gets filtered even the android or other devices that have hard coded the dns in order to block those ads but also I'm using unbound as recursive server while the DHCP is also activaded on the ADH/Pi-hole device in order to make sure the traffic goes there.

So I need to block:

  • TLS
  • DoH

I read in other web, that I could create two tables a "nat" and "filter" on nftables

the nat will be a prerouting chain that redirects incoming DNS and DoH/TLS traffic to AdGuard Home DNS/Pi-hole running on my device and the make another table that would be the postrouting chain that masquerades outgoing traffic on the "lan interface"

This would be a nftable configuration but not sure if I can implement in OpenWrt

flush ruleset

table ip nat {
        chain prerouting {
                type nat hook prerouting priority 0;
                iifname "br-lan" ip daddr 10.105.10.1 udp dport 53 dnat to 10.105.10.2:53;
                iifname "br-lan" ip daddr 10.105.10.1 tcp dport 53 dnat to 10.105.10.2:53;
                iifname "br-lan" ip daddr 10.105.10.1 udp dport { 853, 443 } dnat to 10.105.10.2:853;
                iifname "br-lan" ip daddr 10.105.10.1 tcp dport { 853, 443 } dnat to 10.105.10.2:853;
        }

        chain postrouting {
                type nat hook postrouting priority 100;
                oifname "br-lan" masquerade;
        }
}

table ip filter {
        chain input {
                type filter hook input priority 0;
                iifname "br-lan" udp dport 53 accept;
                iifname "br-lan" tcp dport 53 accept;
                iifname "br-lan" udp dport { 853, 443 } accept;
                iifname "br-lan" tcp dport { 853, 443 } accept;
                iifname "br-lan" udp sport { 53, 853, 443 } accept;
                iifname "br-lan" tcp sport { 53, 853, 443 } accept;
                iifname "br-lan" ip saddr 10.105.10.0/24 accept;
                iifname "br-lan" ip daddr 10.105.10.2 udp dport { 67, 68 } accept;
                iifname "br-lan" ip daddr 10.105.10.1 udp dport { 67, 68 } accept;
                iifname "br-lan" ct state related,established accept;
                iifname "br-lan" icmp type echo-request accept;
                iifname "br-lan" ct state invalid drop;
                drop;
        }

        chain forward {
                type filter hook forward priority 0;
                iifname "br-lan" oifname "br-lan" accept;
                iifname "br-lan" oifname "wan" ct state new,related,established accept;
                iifname "br-lan" ip saddr 10.105.10.0/24 accept;
                iifname "br-lan" ct state related,established accept;
                iifname "br-lan" ct state invalid drop;
                drop;
        }

        chain output {
                type filter hook output priority 0;
                oifname "br-lan" accept;
                oifname "wan" ct state new,related,established accept;
                accept;
        }
}

would be this doable o I should think in other options?

You haven't by any chance created a loop ?

Forward att dns traffic to the Pi , including the Pi's own outbound traffic...?

I think you are right I created a loop but I was following the DNS hijacking to intercept the DNS from the documentation from openwrt wiki. But I'm thinking this applies for firewall3 configuration, while the new version is firewall4?

and maybe that is the reason I can't surf on the web. So I deleted the configuration and everything is working fine.

before upgrading my router to the version 22, I was using the method with arp spoofing using the packages

I know I can't divert everything querying port 53 I need to do exceptions for the router and the pihole/adguard.
The router itself should be able to query DNS from the internet normally and the second exception to the rules should be the pihole/adguard machine to be allowed to query the router in turn.

So i was using the module iptables-mod-extra to use addrtype to distinguish between local and non-local addresses. so I used a prerouting and exclude the pihole/adguard and using the mac address of the source making request but not were equal to the pihole/adguard mac addresses and also triggered when the source was a not local address.

anyways, I can't use this method, so i left it when I upgraded to the version 22+ but is getting annoying that some sneaking adds on some android devices are appearing.

I think this should still work ...

uci set firewall.dns_int.name="Redirect-DNS"
uci set firewall.dns_int.src_ip="!10.105.10.2"
uci set firewall.dns_int.dest_ip="10.105.10.2"
uci -q delete firewall.dns_masq
uci set firewall.dns_masq="nat"
uci set firewall.dns_masq.name="Masquerade-DNS"
uci set firewall.dns_masq.src="lan"
uci set firewall.dns_masq.dest_ip="10.105.10.2"
uci set firewall.dns_masq.dest_port="53"
uci set firewall.dns_masq.proto="tcp udp"
uci set firewall.dns_masq.target="MASQUERADE"
uci commit firewall

Note the ! in the 2nd line, excluding your own DNS' IP from the rule, and avoiding the loop.

You could also REJECT all external DNS traffic, except for queries coming from 10.105.10.2, and hope all devices will fall back to the DNS IP provided by the DHCP.

thank you I see the ! excludes the ip and avoid the loop.

So this is what I understand

  • The first rule redirects DNS traffic on the LAN network to a specific DNS server (10.105.10.2) (AGH/Pi-hole device).
  • The second rule excludes the IP address 10.105.10.2 (AGH/Pi-hole device) from the first rule.
  • The third rule specifies the destination IP address for the first rule (10.105.10.2) (AGH/Pi-hole device).
  • The fourth rule deletes any existing rule for masquerading DNS traffic.
  • The fifth rule sets up a new NAT rule for DNS traffic.
  • The sixth rule sets the name of the new NAT rule for DNS traffic to "Masquerade-DNS".
  • The seventh rule sets the source zone for the new NAT rule for DNS traffic to the LAN network.
  • The eighth rule sets the destination IP address for the new NAT rule for DNS traffic to 10.105.10.2 (AGH/Pi-hole device).
  • The ninth rule sets the destination port for the new NAT rule for DNS traffic to 53.
  • The tenth rule sets the protocol for the new NAT rule for DNS traffic to TCP and UDP.
  • The eleventh rule sets the target for the new NAT rule for DNS traffic to MASQUERADE, which modifies the source IP address of the DNS traffic to the IP address of the OpenWRT router.
  • The final command commits the changes to the OpenWRT firewall configuration

I wish we have a custom section on the firewall tab just to paste the NFTables/firewall4 script :frowning:

now I need to block the DoH and DoT, those sneaky ads are getting me crazy. I'll report back as soon advance on this.

There is an error and fixed here at least for me, you will get an error for invalid sintaxis:

uci -q delete firewall.dns_int
uci set firewall.dns_int.name="Redirect-DNS"
uci set firewall.dns_int.src_ip="!10.105.10.2"
uci set firewall.dns_int.dest_ip="10.105.10.2"
uci -q delete firewall.dns_masq
uci set firewall.dns_masq="nat"
uci set firewall.dns_masq.name="Masquerade-DNS"
uci set firewall.dns_masq.src="lan"
uci set firewall.dns_masq.dest_ip="10.105.10.2"
uci set firewall.dns_masq.dest_port="53"
uci set firewall.dns_masq.proto="tcp udp"
uci set firewall.dns_masq.target="MASQUERADE"
uci commit firewall

So the solution was after this you need to take control of DoH. Since there is not properly way to put custom firewall rules. In case you are doing NFT tables/Firewall 4, because the wiki is only for IPtables/Firewall3.

for NFtables, create a script via Hotplug that triggers on the WAN downloads the script from the github with the public DoH so it can block it on the list for the firewall. Its a PITA. I would avoid this route and if really important to block DoH/DoT don't do it with an external device like a pi, at least with the new openwrt 22.x

move to use opnsense/pfsense o move to a commercial solution, the recommended solution is more like a frankenstein mix and match route how to force or trick with openwrt 22.x with extra tools to grab/hijack the dns.

NFtables is more easy simply on linux but I really recommend to read the documentation on OpenWrt, it will save a lot of pain for all the people who is looking to block DoT/DoH with an external device and using dhcp/dns server instead the openwrt.

this is my script for NFTAbles doing my setup obviously not using OpenWrt but the power of NFtables to grab everything is really nice and is installed on debian.

flush ruleset

table ip nat {
        chain prerouting {
                type nat hook prerouting priority 0;
                iifname "br-lan" ip daddr 10.105.10.1 udp dport 53 dnat to 10.105.10.2:53;
                iifname "br-lan" ip daddr 10.105.10.1 tcp dport 53 dnat to 10.105.10.2:53;
                iifname "br-lan" ip daddr 10.105.10.1 udp dport { 853, 443 } dnat to 10.105.10.2:853;
                iifname "br-lan" ip daddr 10.105.10.1 tcp dport { 853, 443 } dnat to 10.105.10.2:853;
        }

        chain postrouting {
                type nat hook postrouting priority 100;
                oifname "br-lan" masquerade;
        }
}

table ip filter {
        chain input {
                type filter hook input priority 0;
                iifname "br-lan" udp dport 53 accept;
                iifname "br-lan" tcp dport 53 accept;
                iifname "br-lan" udp dport { 853, 443 } accept;
                iifname "br-lan" tcp dport { 853, 443 } accept;