Prevent DNS sharing between interfaces

I successfully completed the task of setting up unique DNS per interface, and even force specific DNS to be used inside VPN :wink: . Here are the notes:

This page explains DNS testing and validation. Implementing DoH/DoT blocks and DNS redirection. Finally what went wrong with PBR.

Useful Links:

Notes

  • These are just personal notes, they haven't been completely written for wider audience. Hope it makes sense, if you have a question let me know.
  • There might be domains that initially do not appear in web service interface below for DNS testing (Method 1) and inside VPN iprules logs (Method 2). This will be fixed with DNS redirection (continue reading).
  • This page assumes you have Unbound configured
  • Replaced my initial implementation of (Interface -> dnsmasq -> DNS server) with (Interface -> AdGuard Home -> DNS Server) because AdGuard seems to support defining clients with custom upstream DNS server and I already use AdGuard for ad blocking so why not :slight_smile:

Test DNS Host source IP

This test will inform you which IP address is used to perform DNS query. It can be your home ISP, or your VPN server. You ideally want to see VPN server IP when using VPN, otherwise you have DNS leak.

Method 1

  1. Setup account on AdGuard / NextDNS / Cloudflare (account might not be necessary as some provide trial service).
  2. Setup DNS on router to point to service of your choice..
  3. Above services will want you to "link your device". Do it on your home network without VPN connection.
  4. Check connection and logs from above services' web interface after visiting random website, you should see entries being shown.
  5. Enable VPN on your device and access different random website.
  6. Check back in web interface if you are still getting hits, if you do that means you are using home ISP network for DNS and there is a leak.

Method 2

If you have direct access to your VPN server, SSH inside and add iptables/nftables configuration. ( I only give iptables example because I copy-paste old post with ready solution :slight_smile: )

  1. Setup logging for FORWARD rule. Double check this is your wireguard interface (wg0) by running 'ip a' and then run:
sudo iptables -I FORWARD -i wg0 -j LOG --log-prefix 'tunnel wireguard iptables [INPUT]: ' --log-level 7
sudo iptables -I FORWARD -o wg0 -j LOG --log-prefix 'tunnel wireguard iptables [OUTPUT]: ' --log-level 7
  1. Once device is connected to VPN server, you should see DNS IP coming from the wg interface (usually wg0) in your logs. Such as 1.1.1.1 or 8.8.8.8, depending on which DNS server you specified.
    When you make a connection from your home desktop/laptop, you should see DNS IP here coming from the wg0 interface ()

AdGuard Forwarding

  1. Change dnsmasq port from 53 to 5333 to prevent conflicts with unbound and AdGuard (or remove completely if you have another svc dealing with DHCP? (confirm)), nano /etc/config/dhcp:
config dnsmasq
        option port '5333'
  1. Enable AdGuard home and point it to your current DNS service on openwrt router (dnsmasq)
  2. Ensure AdGuard listens on port 53
  3. In AdGuard home, go to Settings -> Client Settings -> Add Client. Create unique client:
- Client name: VPN Ethernet Interface
- Identifier: 192.168.4.0/24
- Use global settings - leave this checked
- Upstream DNS Servers: 9.9.9.9 # Later PBR rule will forward this DNS to VPN

DoH Block

  1. Go to AdGuard Home -> Filters -> Add Blocklist -> Choose from list -> Security Section -> Select 'HaGeZi's Encrypted DNS/VPN/TOR/Proxy Bypass' and Save.
  2. Go to OpenWRT and install banip. Do NOT install luci-banip, it seems to have been erroring when attempting to start service until you manually restart from terminal.
  3. Enable so it launches on reboot and immediately start banip service in OpenWRT.
  4. Ensure config in /etc/config/banip, more specifically list ban_feed 'doh'.
config banip 'global'
        option ban_enabled '1'
        option ban_debug '1'
        option ban_autodetect '1'
        list ban_logterm 'Exit before auth from'
        list ban_logterm 'luci: failed login'
        option ban_fetchretry '5'
        option ban_nicelimit '0'
        option ban_filelimit '1024'
        option ban_deduplicate '1'
        option ban_nftpriority '-100'
        option ban_icmplimit '25'
        option ban_synlimit '10'
        option ban_udplimit '100'
        option ban_nftpolicy 'memory'
        option ban_nftretry '5'
        option ban_blockpolicy 'drop'
        option ban_nftloglevel 'warn'
        option ban_logprerouting '0'
        option ban_loginbound '0'
        option ban_logoutbound '0'
        option ban_loglimit '100'
        option ban_autoallowlist '1'
        option ban_autoallowuplink 'subnet'
        option ban_autoblocklist '1'
        option ban_allowlistonly '0'
        list ban_feed 'doh'
        option ban_fetchcmd 'curl'
        option ban_protov4 '1'
        list ban_ifv4 'wan'
        list ban_dev 'eth0'

  1. /etc/init.d/banip stop; /etc/init.d/banip disable; /etc/init.d/banip start; /etc/init.d/banip enable; /etc/init.d/banip status - restart service.
  2. logread - check latest logs, it should pull DOH list.
  3. nft list table inet banIP - list nftables config for banIP, try curl or ping to an example address, there should be no connection. Important: do not do it from Router side, it doesn't block router-initiated connections.
  4. As of today (16 Aug '25), couple of services are blocked unintentionally such as github.io. Planned be investigated banIP support thread - #2847 by dibdot .

DoT Block

  1. Add rule in /etc/config/firewall to block all DoT traffic.:
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'

DNS Redirection

  1. Inside /etc/unbound/unbound.conf, apply these properties to help with debugging:
server:
  log-queries: yes
  use-syslog: yes
  verbosity: 1
  1. /etc/init.d/unbound restart - restart the service.
  2. Check DNS queries that you are receiving through logread -f. There might be some websites that you do not see here when visiting, let's implement DNS redirection now.
  3. Inside /etc/config/firewall, apply this config (192.168.1.1 is the IP where your DNS is located):
config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'Redirect DNS'
        option family 'ipv4'
        option src 'lan'
        option src_dport '53'
        option dest_ip '192.168.1.1'
        option dest_port '53'

PBR VPN Dns

Force DNS use (9.9.9.9) inside VPN by implementing PBR policy. We do not define port here because for my use case, I do not want to forward every DNS request to VPN. I want other local network (192.168.1.0/24) to forward DNS to Unbound.

/etc/config/pbr

config policy
        option name 'Force Forward DNS to WG'
        option interface 'wg_client'
        option dest_addr '9.9.9.9'
        option chain 'output'

Outcome

  • Unique DNS per interface :white_check_mark:
  • Force DNS use inside VPN :white_check_mark:
  • Disabled DoT and DoH to force use of port 53 DNS. Do note this is not a complete solution since there could always be private addresses for DoH. :white_check_mark:
  • Redirected DNS queries to your DNS server, we’ve had a couple of websites that completely avoided our DNS until DNS Redirection was in effect :white_check_mark:

----- END

What didn't go well?

  • Setting this PBR to redirect any DNS to wireguard from VPN ethernet interface. Maybe it is because the src_addr is not exactly 192.168.4.0/24 during DNS query, but I need this src_addr if I specify port otherwise everything will be sent to VPN, so instead we have the IP solution above. But that would be perfect if it worked :smiley:
config policy
        option name 'Redirect DNS to WG'
        option src_addr '192.168.4.0/24'
        option dest_port '53'
        option interface 'wg_client'
        option chain 'output'