I have a Windows client connected to a Wi-Fi hotspot:
Wireless LAN adapter Wireless Network Connection 2:
Connection-specific DNS Suffix . :
Description . . . . . . . . . . . : Atheros Wireless Network Adapter
DHCP Enabled. . . . . . . . . . . : Yes
Autoconfiguration Enabled . . . . : Yes
IPv4 Address. . . . . . . . . . . : 192.168.43.110(Preferred)
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.43.1
DHCP Server . . . . . . . . . . . : 192.168.43.1
DNS Servers . . . . . . . . . . . : 192.168.43.1
NetBIOS over Tcpip. . . . . . . . : Disabled
The Wi-Fi hotspot has its own DNS (as seen above) which resolves any NXDOMAIN to an advertising 'search page' - this is unwanted behavior. This malicious DNS server is initially needed to get past the Wi-Fi's captive portal, so I can't just set a static DNS to override it.
I then connect to my home network using OpenVPN. Server configuration:
server 10.1.1.0 255.255.255.0
proto udp
dev tun21
push "route 10.1.0.0 255.255.254.0" (my home IP subnet)
push "dhcp-option DOMAIN local"
push "dhcp-option DNS 10.1.0.8"
client-to-client
The OpenVPN server is on 10.1.0.1
, my home gateway.
The DNS server is pihole on 10.1.0.8
.
Client configuration:
client
dev tun
proto udp
remote mydynip.net
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
dhcp-option DNS 10.1.0.8 (I tried adding this for redundancy, has no effect)
The OpenVPN connection succeeds:
Ethernet adapter Local Area Connection 3:
Connection-specific DNS Suffix . : local
Description . . . . . . . . . . . : TAP-Windows Adapter V9
DHCP Enabled. . . . . . . . . . . : Yes
Autoconfiguration Enabled . . . . : Yes
IPv4 Address. . . . . . . . . . . : 10.1.1.6(Preferred)
Subnet Mask . . . . . . . . . . . : 255.255.255.252
Default Gateway . . . . . . . . . :
DHCP Server . . . . . . . . . . . : 10.1.1.5
DNS Servers . . . . . . . . . . . : 10.1.0.8
Now, if the Windows client looks up a domain that does exist, everything works as it should. For example:
>ping mypc.local
Pinging mypc.local [10.1.0.2] with 32 bytes of data:
Reply from 10.1.0.2: bytes=32 time=60ms TTL=127
...
... and I see this in the pihole query log (all normal):
Time Type Domain Client Status Reply
2019-07-16... A mypc.local gateway.local OK (forwarded) IP (2.5ms)
However, If I look up a nonexistent domain, even with the .local
prefix, the domain resolves to an advertising page(!) :
>ping nonexist.local
Pinging nonexist.local [198.xx.xx.xx (!!!)] with 32 bytes of data:
...
The query does pass though the pihole first:
Time Type Domain Client Status Reply
2019-07-16... A nonexist.local gateway.local OK (forwarded) NXDOMAIN (2.5ms)
...but it seems that upon receipt of NXDOMAIN the Windows client then tries the Wi-Fi hotspot's malicious DNS server! How do I stop this behavior?
Stuff I tried:
Adding redirect-gateway def1
to the client OpenVPN config nicely redirects all traffic through the VPN, but has no effect at all on the DNS behavior depicted above. It effectively makes my home gateway (gateway.local)
connect to the advertising 'search page' and forward it to the Windows client through the OpenVPN tunnel. At this point, though, the DNS query has already been leaked to the Wi-Fi hotspot's DNS server.
Here's what looks like a possible solution:
If I have the Windows client look up a domain that is blocked on the pihole, Windows does not forward the request to the Wi-Fi hotspot's DNS:
>ping googletagservices.com
Ping request could not find host...
...in pihole query log:
Time Type Domain Client Status Reply
2019-07-16... A goo....com gateway.local Blocked (gravity) - (0.5ms)
This is because the pihole resolves the address to 0.0.0.0
and the Windows client seems satisfied with that.
The problem is, how do I get pihole to reply to all nonexistent domains with 0.0.0.0
rather than NXDOMAIN
? I couldn't find any option in dnsmasq that would do that...