[Solved] DNS hijacking and VPN

(I'm still pre-coffee, so forgive anything stupid I say. :coffee:)

The priority is the ordering within a hook, with the hooks being the major traversal organizer, so maybe this one is a better map for navigating the terrain: https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

The postrouting hook sees stuff "almost" last, and srcnat = 100* priority is also highest = latest, so the srcnat stuff happens just before egress. The dstnat_lan chain occurs on the prerouting hook, so is pretty early in the processing, so it should be the case that your packets to port 53 get intercepted first.

(* - looks like you've already found the symbol -> number table for the priorities, anyone interested search 'srcnat' here for numeric priority values: https://www.netfilter.org/projects/nftables/manpage.html)

Using a simplified path through that wikipedia diagram, you need only consider a path that looks grossly like this for local client on the lan to remote client on the wan.

lan-packet -> prerouting -> forward -> postrouting -> output -> wan-packet

(No input as we assume this packet is being forwarded.)

WG is going to srcnat those lan packets at the end of the postrouting step, then off they go into space.

So, in your item 1, unless there's something on the WG interface to direct packets into that dstnat_lan (sub)chain, I don't think WG traffic will see it at all. Try this one and see if you find a "WGINTERFACE" jump in there:

$ nft list chain inet fw4 dstnat
table inet fw4 {
        chain dstnat {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "br-lan" jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
                iifname "eth0" jump dstnat_wan comment "!fw4: Handle wan IPv4/IPv6 dstnat traffic"
        }
}

Yup, your item 2 should be intercepting all port 853 traffic since that checks priort to any interface-specific rules.

In item 3, if the banIP rules simply ignore interface names (i.e., no iifname or oifname clauses), then they're probably applied to all traffic and should "just work."


Circling around slightly...

You can test plain DNS interception pretty easily, and the DoH by-name blocking by trying to look up one of the well known DoH servers (I always use doh.dns.apple.com, as it is always on everyone's lists).

I did this on my router, where I can bypass the rules applied to the LAN. If you do it on a client, you should see both nslookups fail to resolve, so you could test it with WG off and WG on to see if there are differences.

$ nslookup doh.dns.apple.com
Server:         127.0.0.1
Address:        127.0.0.1:53

** server can't find doh.dns.apple.com: NXDOMAIN

# I'm on the router, so I can bypass my DoH blocking and actually get a result; gives NXDOMAIN on my clients:
$ nslookup doh.dns.apple.com 9.9.9.9
Server:         9.9.9.9
Address:        9.9.9.9:53

Non-authoritative answer:
doh.dns.apple.com       canonical name = doh.dns.apple.com.v.aaplimg.com
Name:   doh.dns.apple.com.v.aaplimg.com
Address: 17.253.82.113
blah blah blah...
1 Like