Prevent DNS sharing between interfaces

Hi,

Thank you all for your time responding to my recent posts. I have been trying to setup my VPN solution and I'm almost there. So here is my question.

I set custom DNS server per network interface, yet they seem to be sharing DNS servers between each other when checking against DNS leak?

Is that misconfiguration on my part, or is that intended behaviour. If it's intended, what do I change to make DNS per interface, and not allow sharing?

For example, right now my local IP is 192.168.4.106/24 and when I visit dns leak test website, I get Cloudflare / Google / WoodyNet ISPs.

My intended behaviour is that I would only get:

  • WoodyNet (9.9.9.9) if I'm on 192.168.4.X/24.
  • CloudFlare (1.1.1.1) if I'm on 192.168.1.X/24.
    as per config below:
/etc/config/network
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 ula_prefix 'fd45:77bf:4370::/48'
        option packet_steering '1'

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

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        list dns '1.1.1.1'
        option delegate '0'

config interface 'vpn_client'
        option device 'eth3'
        option proto 'static'
        option ipaddr '192.168.4.1'
        option netmask '255.255.255.0'
        list dns '9.9.9.9'
        option delegate '0'

config interface 'wan'
        option device 'eth0'
        option proto 'dhcp'
        option peerdns '0'
        list dns '8.8.8.8'

config interface 'wg_client'
        option proto 'wireguard'
        option private_key '<REDACTED>'
        list addresses '10.9.0.2/24'
        option delegate '0'
        list dns '9.9.9.9'

config wireguard_wg_client
        option description 'Imported peer configuration'
        option public_key '<REDACTED>'
        option endpoint_host '<REDACTED>'
        option endpoint_port '<REDACTED>'
        list allowed_ips '0.0.0.0/0'

/etc/config/dhcp
config dnsmasq
        option port '53'
        option domainneeded '1'
        option boguspriv '1'
        option filterwin2k '0'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option nonegcache '0'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option nonwildcard '1'
        option localservice '1'
        option ednspacket_max '1232'
        option filter_aaaa '0'
        option filter_a '0'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'

config dhcp 'vpn_client'
        option interface 'vpn_client'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'

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'
/etc/config/firewall
config defaults
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'

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

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

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 rule
        option src 'vpn_client'
        option name 'Allow-LAN-DHCP-DNS'
        option dest_port '53 67'
        option target 'ACCEPT'

config rule
        option dest 'vpn_client'
        option name 'Allow-IN-DHCP-DNS'
        option src_port '53 67'
        option target 'ACCEPT'

config zone
        option name 'vpn_client'
        option input 'ACCEPT'
        option output 'REJECT'
        option forward 'REJECT'
        list network 'vpn_client'
        option family 'ipv4'

config zone
        option name 'wg_client'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wg_client'
        option family 'ipv4'

config forwarding
        option src 'vpn_client'
        option dest 'wg_client'

config forwarding
        option src 'lan'
        option dest 'wan'

/etc/config/pbr
config pbr 'config'
        option debug_dnsmasq '0'
        option enabled '1'
        option verbosity '2'
        option strict_enforcement '1'
        option resolver_set 'dnsmasq.nftset'
        list resolver_instance '*'
        option ipv6_enabled '0'
        list ignored_interface 'vpnserver'
        option boot_timeout '30'
        option rule_create_option 'add'
        option procd_boot_trigger_delay '5000'
        option procd_reload_delay '1'
        option webui_show_ignore_target '0'
        option nft_rule_counter '0'
        option nft_set_auto_merge '1'
        option nft_set_counter '0'
        option nft_set_flags_interval '1'
        option nft_set_flags_timeout '0'
        option nft_set_policy 'performance'
        list webui_supported_protocol 'all'
        list webui_supported_protocol 'tcp'
        list webui_supported_protocol 'udp'
        list webui_supported_protocol 'tcp udp'
        list webui_supported_protocol 'icmp'

config include
        option path '/usr/share/pbr/pbr.user.aws'
        option enabled '0'

config include
        option path '/usr/share/pbr/pbr.user.netflix'
        option enabled '0'

config policy
        option name 'Ignore Local Requests'
        option interface 'ignore'
        option dest_addr '10.0.0.0/24 10.0.1.0/24 192.168.100.0/24 192.168.1.0/24'
        option enabled '0'

config policy
        option name 'Plex/Emby Local Server'
        option interface 'wan'
        option src_port '8096 8920 32400'
        option enabled '0'

config policy
        option name 'Plex/Emby Remote Servers'
        option interface 'wan'
        option dest_addr 'plex.tv my.plexapp.com emby.media app.emby.media tv.emby.media'
        option enabled '0'

config policy
        option interface 'wg_client'
        option name 'Redirect Ethernet 4 to VPN'
        option src_addr '192.168.4.0/24'

/etc/config/uhttpd
config uhttpd 'main'
        list listen_http '0.0.0.0:80'
        list listen_http '[::]:80'
        list listen_https '0.0.0.0:443'
        list listen_https '[::]:443'
        option redirect_https '0'
        option home '/www'
        option rfc1918_filter '1'
        option max_requests '3'
        option max_connections '100'
        option cert '/etc/uhttpd.crt'
        option key '/etc/uhttpd.key'
        option cgi_prefix '/cgi-bin'
        list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
        option script_timeout '60'
        option network_timeout '30'
        option http_keepalive '20'
        option tcp_keepalive '1'
        option ubus_prefix '/ubus'

config cert 'defaults'
        option days '397'
        option key_type 'ec'
        option bits '2048'
        option ec_curve 'P-256'
        option country 'ZZ'
        option state 'Somewhere'
        option location 'Unknown'
        option commonname 'OpenWrt'
/etc/os-release

NAME="OpenWrt"
VERSION="24.10.2"
ID="openwrt"
ID_LIKE="lede openwrt"
PRETTY_NAME="OpenWrt 24.10.2"
VERSION_ID="24.10.2"
HOME_URL="https://openwrt.org/"
BUG_URL="https://bugs.openwrt.org/"
SUPPORT_URL="https://forum.openwrt.org/"
BUILD_ID="r28739-d9340319c6"
OPENWRT_BOARD="x86/64"
OPENWRT_ARCH="x86_64"
OPENWRT_TAINTS=""
OPENWRT_DEVICE_MANUFACTURER="OpenWrt"
OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/"
OPENWRT_DEVICE_PRODUCT="Generic"
OPENWRT_DEVICE_REVISION="v0"
OPENWRT_RELEASE="OpenWrt 24.10.2 r28739-d9340319c6"
OPENWRT_BUILD_DATE="1750711236"

/ edit

Loads of resources I found, but apparently its working as intended.

Example: [Solved] DNS query sent on wrong interface - #2 by trendy

/ edit 2

I think I will attempt below setup. I will update thread when I succeed

Interface 1 (192.168.1.0/24) → dnsmasq → unbound local resolver

Interface 2 (192.168.1.0/24) → dnsmasq-2 → 9.9.9.9

1 Like

You can use DHCP Option No. 6 to issue the desired DNS servers to the clients. You may have to ensure the local DNS isn't still announced via IPv6.

This is configured under each interface in /etc/config/dhcp

e.g., for Goo$le:

list dhcp_option '6,8.8.8.8,8.8.4.4'

You could also perform a firewall redirect on unencrypted port 53/udp to the desired destination server by interface/subnet. This is more complex.

1 Like

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'

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