How to reroute all outgoing packets to port 53 locally?

It's the well-known problem: Android devices use hardcoded Google DNS 8.8.8.8, so local names cannot be resolved except the local name of the router itself. Other devices from lan can resolve names perfectly.

Proposal for solution from a post from 2018:

Therefore @eduperez suggest to use

iptables -t nat -A PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 192.168.1.1
iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 53 -j DNAT --to 192.168.1.1

However this doesn't work for me. First of all, after reading why opkg upgrade is so awful I was hesitating to install anything at all. So I tried with Luci first:

First attempt:

I added a rule in Network > Firewall > NAT Rules and I will provide the resulting config via uci:

=> uci show firewall.@nat[0]
firewall.cfg0e93c8=nat
firewall.cfg0e93c8.name='DNSReroute'
firewall.cfg0e93c8.proto='tcp' 'udp'
firewall.cfg0e93c8.dest_port='53'
firewall.cfg0e93c8.target='SNAT'
firewall.cfg0e93c8.snat_ip='192.168.1.1'
firewall.cfg0e93c8.snat_port='53'
firewall.cfg0e93c8.device='br-lan'
firewall.cfg0e93c8.src='*'

There is no DNAT available, hence SNAT. I cleared the Google Chrome cache on my Android phone at chrome://net-internals/#dns and reconnected to the Wi-Fi with DHCP enabled.

Second attempt:

To try eduperez's approach I disabled what Luci did (firewall.cfg0e93c8.enabled='0') and installed iptables v1.8.7 (opkg install iptables). The options are different in this version. There is no --to option or a --to-destination like on https://linux.die.net/man/8/iptables. However --destination did work but I got the error

iptables v1.8.7 (nf_tables): Chain 'DNAT' does not exist

Third attempt:

Didn't work either:

=> nft list ruleset
table inet fw4 {
[...]
  chain dstnat_lan {
    meta nfproto ipv4 tcp dport 53 counter packets 0 bytes 0 redirect to :53 comment "!fw4: Intercept-DNS"
    meta nfproto ipv4 udp dport 53 counter packets 1 bytes 60 redirect to :53 comment "!fw4: Intercept-DNS"
  }
[...]

=> uci show firewall.@redirect[0]
firewall.@redirect[0]=redirect
firewall.@redirect[0].target='DNAT'
firewall.@redirect[0].name='Intercept-DNS'
firewall.@redirect[0].src='lan'
firewall.@redirect[0].src_dport='53'

# Intercept IPv6 DNS traffic
=> uci set firewall.dns_int.family="any"
uci: Invalid argument

From here I don't know what to try next. I know some Linux but never understood iptables. I'm wondering if I should put wlan1 together with lan inside br-lan?

Additional information:

This is a very fresh installation of the current OpenWrt 22.03 on a Linksys MR8300. I did not change anything regarding br-lan, vlan or firewall. The device has three wlan devices and my phone is connected via wlan1:

wireless.radio1=wifi-device
wireless.radio1.type='mac80211'
wireless.radio1.path='platform/soc/a000000.wifi'
wireless.radio1.band='2g'
wireless.radio1.htmode='HT20'
wireless.radio1.channel='10'
wireless.radio1.country='DE'
wireless.radio1.cell_density='0'
wireless.default_radio1=wifi-iface
wireless.default_radio1.device='radio1'
wireless.default_radio1.network='lan'
wireless.default_radio1.mode='ap'
wireless.default_radio1.ssid='MyWiFi'
wireless.default_radio1.encryption='psk2'
wireless.default_radio1.key='redacted'

This might also be interesting:

=> uci show firewall.cfg0892bd
firewall.cfg0892bd=rule
firewall.cfg0892bd.name='Allow-DHCPv6'
firewall.cfg0892bd.src='wan'
firewall.cfg0892bd.proto='udp'
firewall.cfg0892bd.dest_port='546'
firewall.cfg0892bd.family='ipv6'
firewall.cfg0892bd.target='ACCEPT'

I'm aware that there are many threads regarding the same issue with Android devices and local DNS resolving. At this point I'm lost. Is there some kind of logfiles or "Wireshark" in OpenWrt that can use to watch the route of DNS traffic? Any help will be appreciated.

The DNS Hijacking wiki link works for me. My rule is slightly different as I have pi-hole running on 10.0.4.250 on the lxc zone but you would just use input as the wiki recommends.

config redirect
  option target 'DNAT'
  option name 'Intercept-DNS'
  option src 'iot'
  option src_dport '53'
  option dest 'lxc'
  option dest_ip '10.0.4.250'
  option dest_port '53'
2 Likes

I tried the Web interface instructions but let me try the CLI instead...

Nope, nothing changed. This is my config now:

=> uci show firewall.dns_int
firewall.dns_int=redirect
firewall.dns_int.name='Intercept-DNS2'
firewall.dns_int.src='lan'
firewall.dns_int.src_dport='53'
firewall.dns_int.proto='tcp udp'
firewall.dns_int.target='DNAT'

Next attempt:

Now let me instead use your lines. I found that you must have pasted the lines from /etc/config/firewall. I added these lines into that file:

config redirect
  option target 'DNAT'
  option name 'Intercept-DNS3'
  option src 'lan'
  option src_dport '53'
  option dest 'wan'
  option dest_ip '192.168.1.1'
  option dest_port '53'

After a firewall restart I still get the error DNS_PROBE_FINISHED_NXDOMAIN. If I change option dest_ip to 127.0.0.1 I get only DNS_PROBE_STARTED. This confirms that lan is the correct value for src.

Not sure what to tell you beyond that what I have is working on my side.

% dig walmart.com @9.9.9.9

; <<>> DiG 9.18.8 <<>> walmart.com @9.9.9.9
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19994
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;walmart.com.			IN	A

;; ANSWER SECTION:
walmart.com.		120	IN	A	161.165.150.170
walmart.com.		120	IN	A	161.170.232.170

;; Query time: 23 msec
;; SERVER: 9.9.9.9#53(9.9.9.9) (UDP)
;; WHEN: Sat Oct 29 09:14:00 EDT 2022
;; MSG SIZE  rcvd: 72

Despite dig returning the server was 9.9.9.9 I see an entry in my pi-hole log proving that the forwarded port works.

2022-10-29 09:14:00	A	walmart.com	quadruple.lan	OK (answered by one.one.one.one#53)
INSECURE	IP (22.1ms)

Here is a screenshot of the LuCI entry but again, I just followed the wiki and substituted my pihole stuff for the router/input.


1 Like

Is the Android using its Private DNS feature (or whatever it’s called)? Could it be using IPv6 DNS? You can add option family '*' to your redirect rule to capture both IPv4 and IPv6, but don’t specify a dest_ip address or else it won’t work.

1 Like

I'm using:

config redirect
	option target 'DNAT'
	option src 'lan'
	option src_dport '53'
	option name 'Intercept-DNS-53'

Taken from: https://openwrt.org/docs/guide-user/firewall/fw3_configurations/intercept_dns

Did you try taking out the destination zone so it's unspecified and no internal port or address so it defaults to any?

I tried to follow all your suggestions but nothing helped. I guess troubleshooting is extra hard because all I can do on my phone is disable/enable WiFi and clear the Chrome cache. Maybe that's not enough, I don't know.

Thank you very much for your support so far! For now I will just configure the apps on my phone to talk to the IP addresses.

Maybe my approach is unnecessary because I'm going to install AdGuard Home anyway.

I will revert all changes now and continue installing AdGuard Home. Thanks again for your support and your time! :slight_smile:

are you sure your android phone is using plain DNS and not DNS-over-HTTPS for example? as in latter it will not use port 53 but 443 which is used for normal HTTPS as well.

OT but this fact would be enough for me to not support that platform.

Thanks for the hint. I tried enabling each one of my redirects one at a time, and cleared my Chrome cache between each one but nothing helped.

I definitely need to look inside the packages with tcpdump or Wireshark. I just quickly changed my wireless mode to monitor but there is a lot more to configure I guess, before I can really see something. So I will first spend my time on AdGuard Home before I dig deeper into this problem.

For summary, this is the configs I have so far, temporarily using incoming 443 instead of 53. There are some obvious errors in some. All are disabled now.

config redirect
        option target 'DNAT'
        option name 'Intercept-DNS1'
        option src 'lan'
        option src_dport '443'
        option enabled '0'

config redirect 'dns_int'
        option name 'Intercept-DNS2'
        option src 'lan'
        option src_dport '443'
        option proto 'tcp udp'
        option target 'DNAT'
        option enabled '0'

config redirect
        option target 'DNAT'
        option name 'Intercept-DNS3'
        option src 'lan'
        option src_dport '443'
        option dest 'wan'
        option dest_ip '192.168.1.1'
        option dest_port '53'
        option family '*'
        option enabled '0'

config redirect
        option dest 'wan'
        option target 'DNAT'
        option name 'Intercept-DNS4'
        option src 'lan'
        option src_dport '443'
        option dest_ip '192.168.1.1'
        option dest_port '53'
        option family '*'
        option enabled '0'

I just installed tcpdump and could immediately start sniffing packets. Nice!

=> tcpdump -i wlan2 host 192.168.1.31 -U -s0
21:20:40.412117 IP samsung.lan.15287 > dns.google.53: 15319+ A? google.com. (28)
21:20:40.428509 IP dns.google.53 > samsung.lan.15287: 15319 1/0/0 A 142.250.185.142 (44)

=> tcpdump -n -i wlan2 host 192.168.1.31
21:23:56.517090 IP 192.168.1.31.18010 > 8.8.4.4.53: 53875+ A? google.com. (28)
21:23:56.532086 IP 8.8.4.4.53 > 192.168.1.31.18010: 53875 1/0/0 A 142.250.186.174 (44)

Ok, its ports 53, not 443. I'll later enable my redirect configs and see which one will cause changes in tcpdump.

Here's a big FU to Google, using 8.8.4.4 despite I set 192.168.1.1 for DNS 1 and 2 on my phone using static lease now.

I'm seriously wondering how this has ever worked before. I was on OpenWrt 21, I had the same phone, I did nothing to mitigate Android's silly behaviour. I wasn't even aware of...

EDIT:

I missed something before, it contains my servername I'm trying to reach all day:

21:18:57.297106 IP6 fdbd:8e42:93c1:0:xxxx:xxxx:xxxx:xxxx.36678 > fdbd:8e42:93c1::1.53: 7235+ AAAA? myserver. (26)
21:18:57.298425 IP6 fdbd:8e42:93c1:0:xxxx:xxxx:xxxx:xxxx.46390 > fdbd:8e42:93c1::1.53: 37208+ A? myserver. (26)

From my PC I can connect to http://myserver or http://myserver.lan

config redirect
        option dest 'lan'
        option target 'DNAT'
        option src 'lan'
        option src_dport '53'
        option dest_ip '192.168.1.1'
        option dest_port '53'
        option name 'hijack DNS lan'

this is working for me: it creates a nftables rule:

chain dstnat_lan {
                meta nfproto ipv4 tcp dport 53 counter packets 3 bytes 180 dnat ip to 192.168.1.1:53 comment "!fw4: hijack DNS lan"
                meta nfproto ipv4 udp dport 53 counter packets 553 bytes 37456 dnat ip to 192.168.1.1:53 comment "!fw4: hijack DNS lan"

from my my PC doing nslookup <host> 8.8.8.8 i can see counter is increasing, also in owrt DNS log i can find host is resolved.

this rule is incorrect as it tells that 192.168.1.1 is in wan zone but i guess that's your lan intefaces ip address.

Thanks! Applying your config I get the same result:

chain dstnat_lan {
        meta nfproto ipv4 tcp dport 53 counter packets 1 bytes 40 dnat ip to 192.168.1.1:53 comment "!fw4: hijack DNS lan"
        meta nfproto ipv4 udp dport 53 counter packets 77 bytes 4840 dnat ip to 192.168.1.1:53 comment "!fw4: hijack DNS lan"
        }

But I can't spot any difference in tcpdump. Do you?

8.8.8.8.53 > 192.168.1.31.27021 look suspicious.

22:01:49.676106 IP 192.168.1.31.30794 > 192.168.1.1.53: 15457+ A? myserver.lan. (30)
22:01:49.676112 IP 192.168.1.31.62675 > 192.168.1.1.53: 55161+ AAAA? myserver.lan. (30)
22:01:49.676117 IP 192.168.1.31.17351 > 192.168.1.1.53: 17101+ Type65? myserver.lan. (30)
22:01:49.680048 IP 192.168.1.1.53 > 192.168.1.31.30794: 15457 NXDomain 0/0/0 (30)
22:01:49.684332 IP 192.168.1.1.53 > 192.168.1.31.62675: 55161 NXDomain 0/0/0 (30)
22:01:49.687956 IP 192.168.1.1.53 > 192.168.1.31.17351: 17101 NXDomain 0/0/0 (30)
22:01:49.692927 IP 192.168.1.31.24184 > 192.168.1.1.53: 29739+ A? myserver.lan. (30)
22:01:49.692929 IP 192.168.1.31.7339 > 192.168.1.1.53: 47540+ AAAA? myserver.lan. (30)
22:01:49.693920 IP 192.168.1.1.53 > 192.168.1.31.24184: 29739 NXDomain 0/0/0 (30)
22:01:49.694744 IP 192.168.1.1.53 > 192.168.1.31.7339: 47540 NXDomain 0/0/0 (30)
22:01:49.757350 IP 192.168.1.31.60047 > 192.168.1.1.53: 43743+ A? google.com. (28)
22:01:49.758637 IP 192.168.1.1.53 > 192.168.1.31.60047: 43743 1/0/0 A 142.250.181.238 (44)
22:01:49.762056 IP 192.168.1.31.27021 > 8.8.8.8.53: 47465+ A? google.com. (28)
22:01:49.763033 IP 8.8.8.8.53 > 192.168.1.31.27021: 47465 1/0/0 A 142.250.181.238 (44)
22:01:54.725259 ARP, Request who-has 192.168.1.1 tell 192.168.1.31, length 28
22:01:54.725989 ARP, Reply 192.168.1.1 is-at e8:9f:80:ad:34:33, length 28
22:01:56.308343 IP 192.168.1.31.53280 > 192.168.1.1.53: 19963+ A? www.google.com. (32)
22:01:56.310975 IP 192.168.1.1.53 > 192.168.1.31.53280: 19963 1/0/0 A 142.250.185.100 (48)

I didn't cut the requests to www.google.com because they happen every time I swipe down in Chrome. Yes, this is a single page refresh.

This is when my Windows PC performs nslookup myserver 8.8.8.8 without DNS hijacking:

22:23:08.237523 IP 192.168.1.30.55863 > 8.8.8.8.53: 1+ PTR? 8.8.8.8.in-addr.arpa. (38)
22:23:08.249421 IP 8.8.8.8.53 > 192.168.1.30.55863: 1 1/0/0 PTR dns.google. (62)
22:23:08.250404 IP 192.168.1.30.55864 > 8.8.8.8.53: 2+ A? myserver.lan. (30)
22:23:08.261372 IP 8.8.8.8.53 > 192.168.1.30.55864: 2 NXDomain 0/1/0 (105)
22:23:08.262419 IP 192.168.1.30.55865 > 8.8.8.8.53: 3+ AAAA? myserver.lan. (30)
22:23:08.275251 IP 8.8.8.8.53 > 192.168.1.30.55865: 3 NXDomain 0/1/0 (105)

and with your config for DNS hijacking:

22:26:23.339328 IP 192.168.1.30.61327 > 8.8.8.8.53: 1+ PTR? 8.8.8.8.in-addr.arpa. (38)
22:26:23.358263 IP 8.8.8.8.53 > 192.168.1.30.61327: 1 1/0/0 PTR dns.google. (62)
22:26:23.359261 IP 192.168.1.30.61328 > 8.8.8.8.53: 2+ A? myserver.lan. (30)
22:26:23.360166 IP 8.8.8.8.53 > 192.168.1.30.61328: 2 NXDomain 0/0/0 (30)
22:26:23.360608 IP 192.168.1.30.61329 > 8.8.8.8.53: 3+ AAAA? myserver.lan. (30)
22:26:23.361429 IP 8.8.8.8.53 > 192.168.1.30.61329: 3 NXDomain 0/0/0 (30)

with an ipconfig /flushdns in between. As far as I can tell, the config doesn't work for me. It's not an Android problem. Since we got the same resulting nftables rule I suppose I have more problems than I'm aware of. If I think about it... I wasn't able to reach myserver from the routers ssh. I created a line in `/etc/hosts'. Oh... this is bad. What have I done.

hm, you seem to managed somehow to send dns queries to 8.8.8.8 even for myserver.lan ... maybe time to reset owrt setup, remove any manual things (like tampering /etc/hosts) and just try the hijack rule again.

tcpdump on the LAN side won’t know that 8.8.8.8 is being intercepted. You can monitor 8.8.8.8 on the WAN side to ensure nothing is actually going out to Google DNS.

I have an interesting update. As I said I cannot connect to myserver from myrouter by its hostname without using /etc/hosts. But my Android phone and Windows PC are reachable. Sorry for wasting your time because of my configuration issues on my Debian server. I still have to figure it out, maybe some resolv.conf issues.

Armed with tcpdump -v -i eth0 host 192.168.1.30 and port 53 I tried

nslookup samsung 8.8.8.8 and
nslookup samsung myrouter

I will spare you the full dump. The interesting part is that without DNS hijacking I got

dns.google.53 > windows.lan.63920: 2 NXDomain 0/1/0 (107) and
myrouter.lan.53 > windows.lan.63917: 2* 1/0/0 samsung.lan. A 192.168.1.31 (48)

We can see that 8.8.8.8 cannot resolve samsung but myrouter[.lan] can.

Now enable DNS hijacking, flush dns and try again:

dns.google.53 > windows.lan.51849: 2* 1/0/0 samsung.lan. A 192.168.1.31 (48)
myrouter.lan.53 > windows.lan.51846: 2* 1/0/0 samsung.lan. A 192.168.1.31 (48)

That's it! This is the working config from @grrr2

config redirect
    option dest 'lan'
    option target 'DNAT'
    option src 'lan'
    option src_dport '53'
    option dest_ip '192.168.1.1'
    option dest_port '53'
    option name 'hijack DNS lan'

I thank you all for your support and I highly suggest to opgk install tcpdump. Otherwise it's just a guessing game.

Now I can install AdGuard Home and make things even more complicated :grin:

Just a heads up, adblock, https-dns-proxy and simple-adblock all have features to enable DNS Hijacking on the router without have to create firewall rules manually.

1 Like

Update:

There was a power outage and I had to reboot my server. Now it can be resolved from myrouter without editing /etc/hosts. The server is finally visible in Active DHCP Leases. I should have troubleshooted that first.

Nevertheless, I learned something about firewall redirect and tcpdump. :+1: And the DNS hijacking still seems to be necessary.

@stangri
Good to know, but I will go for AdGuard Home anyway.

1 Like

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