OpenWrt 24.10 + WireGuard + PBR: VLAN traffic tunnels correctly but DNS leaks via router (Unbound/AdGuard)

Hardware / OS

  • Router: GL.iNet GL-MT6000 (Filogic 830)
  • OpenWrt: 24.10.4 (fw4 / nftables)
  • Kernel: 6.6.x
  • VPN: Mullvad WireGuard
  • PBR: pbr 1.2.0-r2 (fw4 nft mode)

Network Design

  • Multiple VLANs on br-lan
  • VLAN20 (10.192.117.0/24) is intended to be VPN-only
  • All other VLANs go out WAN normally

VPN / Routing

  • WireGuard interface wg_mullvad
  • Policy-based routing configured:
src 10.192.117.0/24 → table pbr_wg_mullvad → wg_mullvad
  • PBR rules confirmed via:
nft list chain inet fw4 pbr_prerouting
ip rule show
ip route show table pbr_wg_mullvad
  • VLAN20 traffic does go through the tunnel
  • am.i.mullvad.net confirms VPN for HTTP traffic

DNS Stack

  • AdGuard Home on port 53
  • dnsmasq on port 5353
  • Unbound recursive resolver on port 5335
  • DHCP option 6 for VLAN20:
10.192.117.1
  • Clients send DNS only to router (confirmed via tcpdump)

Observed Problem

  • DNS leak detected on Mullvad’s DNS leak test
  • Leak shows ISP DNS, even though:
    • Clients do NOT contact ISP DNS directly
    • tcpdump on br-lan.20 shows DNS only to 10.192.117.1
  • Leak occurs after DNS reaches router

Evidence

  • tcpdump -ni br-lan.20 port 53 shows:
10.192.117.x → 10.192.117.1:53
  • No direct DNS traffic from clients to WAN
  • Leak appears to be caused by router-originated DNS traffic

Key Insight / Hypothesis

  • PBR only affects forwarded traffic
  • Router-originated DNS (Unbound upstream queries) use:
    • main routing table
    • WAN default route
  • Result: DNS resolves correctly but exits via WAN → leak

What Works

  • Tunnel handshakes and routes are correct
  • VLAN20 traffic flows through WireGuard
  • DNS resolution works (no timeouts)

What Does NOT Fix It

  • Firewall changes
  • MTU changes
  • WireGuard DNS field changes
  • Temporarily disabling IPv6
  • Reinstalling configs
  • Restarting services

What I’m Looking For

  • Correct way to force router-originated DNS traffic (Unbound / AdGuard)
    to follow the same WireGuard routing policy as VLAN20
  • Best practice with PBR + recursive DNS on OpenWrt fw4
  • Whether this should be handled via:
    • PBR output chain rules
    • fwmark-based routing for DNS ports
    • or Unbound interface binding

Basically I have a vpn/wireguard/mullvad tunnel that functions in that traffic travels through it but I am leaking my isp dns ip and I'm not sure what I need to do to make that stop.

Ran some tests and now know:

VLAN20 traffic is correctly policy-routed through WireGuard using PBR, but router-originated DNS traffic (Unbound + AdGuardHome) bypasses PBR and exits via the WAN (IPv4 and IPv6), causing DNS leaks confirmed via tcpdump on eth1.

Please connect to your OpenWrt device using ssh and copy the output of the following commands and post it here using the "Preformatted text </> " button (red circle; this works best in the 'Markdown' composer view in the blue oval):

Screenshot 2025-10-20 at 8.14.14 PM

Remember to redact passwords, VPN keys, MAC addresses and any public IP addresses you may have:

ubus call system board
cat /etc/config/network
cat /etc/config/wireless
cat /etc/config/dhcp
cat /etc/config/firewall
kill -s USR1 dnsmasq ; sleep 1 ; logread -e dnsmasq | tail -10

 ubus call system board
{
        "kernel": "6.6.110",
        "hostname": "OpenWrt",
        "system": "ARMv8 Processor rev 4",
        "model": "GL.iNet GL-MT6000",
        "board_name": "glinet,gl-mt6000",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "24.10.4",
                "revision": "r28959-29397011cc",
                "target": "mediatek/filogic",
                "description": "OpenWrt 24.10.4 r28959-29397011cc",
                "builddate": "1760891865"
        }
}
root@OpenWrt:~# cat /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 'fd2c:2791:1840::/48'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
        list ports 'lan5'

config interface 'lan'
        option device 'br-lan.1'
        option proto 'static'
        option ipaddr '10.65.82.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

config interface 'wan'
        option device 'eth1'
        option proto 'dhcp'
        option macaddr '00:05:1B:D6:42:96'
        option peerdns '0'
        option dns '0.0.0.0'

config interface 'wan6'
        option device 'eth1'
        option proto 'dhcpv6'
        option dns '::'
        option peerdns '0'

config device
        option type '8021q'
        option ifname 'br-lan'
        option vid '10'
        option name 'br-lan.10'

config interface 'lan10'
        option proto 'static'
        option device 'br-lan.10'
        option force_link '0'
        option ipaddr '10.137.228.1'
        option netmask '255.255.255.0'

config bridge-vlan
        option device 'br-lan'
        option vlan '10'
        list ports 'lan3:t'

config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'lan2:u*'
        list ports 'lan3:t'

config bridge-vlan
        option device 'br-lan'
        option vlan '30'
        list ports 'lan3:t'

config interface 'lan30'
        option proto 'static'
        option device 'br-lan.30'
        option ipaddr '10.251.36.1'
        option netmask '255.255.255.0'
        option force_link '0'

config bridge-vlan
        option device 'br-lan'
        option vlan '70'
        list ports 'lan3:t'

config interface 'lan70'
        option proto 'static'
        option device 'br-lan.70'
        option force_link '0'
        option ipaddr '10.42.219.1'
        option netmask '255.255.255.0'

config bridge-vlan
        option device 'br-lan'
        option vlan '60'
        list ports 'lan3:t'

config interface 'lan60'
        option proto 'static'
        option device 'br-lan.60'
        option force_link '0'
        option ipaddr '10.203.157.1'
        option netmask '255.255.255.0'

config bridge-vlan
        option device 'br-lan'
        option vlan '50'
        list ports 'lan3:t'

config interface 'lan50'
        option proto 'none'
        option device 'br-lan.50'

config bridge-vlan
        option device 'br-lan'
        option vlan '20'
        list ports 'lan3:t'

config interface 'lan20'
        option proto 'static'
        option device 'br-lan.20'
        option force_link '0'
        option ipaddr '10.192.117.1'
        option netmask '255.255.255.0'

config bridge-vlan
        option device 'br-lan'
        option vlan '99'
        list ports 'lan3:t'

config interface 'lan99'
        option device 'br-lan.99'
        option proto 'static'
        option ipaddr '10.99.231.1'
        option netmask '255.255.255.0'
        option force_link '0'
        option type 'bridge'

config interface 'wg_mullvad'
        option proto 'wireguard'
        option private_key ''
        list addresses '10.69.50.131/32'
        option mtu '1280'

config wireguard_wg_mullvad
        option description 'Imported peer configuration'
        option public_key 'gH/fZJwc9iLv9fazk09J/DUWT2X7/LFXijRS15e2n34='
        list allowed_ips '0.0.0.0/0'
        list allowed_ips '::0/0'
        option persistent_keepalive '25'
        option endpoint_host '143.244.47.78'
        option endpoint_port '51820'

root@OpenWrt:~# cat /etc/config/wireless

config wifi-device 'radio0'
        option type 'mac80211'
        option path 'platform/soc/18000000.wifi'
        option band '2g'
        option channel 'auto'
        option htmode 'HT40'
        option country 'US'
        option cell_density '0'

config wifi-iface 'default_radio0'
        option device 'radio0'
        option network 'lan'
        option mode 'ap'
        option ssid 'HVAC-221'
        option encryption 'psk2+psk3'
        option key ''

config wifi-device 'radio1'
        option type 'mac80211'
        option path 'platform/soc/18000000.wifi+1'
        option band '5g'
        option channel 'auto'
        option htmode 'HE160'
        option country 'US'
        option cell_density '0'

config wifi-iface 'default_radio1'
        option device 'radio1'
        option network 'lan'
        option mode 'ap'
        option ssid 'HVAC-222'
        option encryption 'psk2+psk3'
        option key ''

config wifi-iface 'wifinet2'
        option device 'radio1'
        option mode 'ap'
        option ssid 'HVAC-223'
        option encryption 'psk2'
        option key ''
        option network 'lan10'

config wifi-iface 'wifinet3'
        option device 'radio1'
        option mode 'ap'
        option ssid ' **Maint-302**'
        option encryption 'psk2'
        option key ''
        option network 'lan30'

config wifi-iface 'wifinet4'
        option device 'radio1'
        option mode 'ap'
        option ssid '**OPS-17A**'
        option encryption 'psk2'
        option key ''
        option network 'lan70'

config wifi-iface 'wifinet5'
        option device 'radio1'
        option mode 'ap'
        option ssid '**Diag-CTRL-9F**'
        option encryption 'psk2'
        option isolate '1'
        option key ''
        option network 'lan60'

config wifi-iface 'wifinet6'
        option device 'radio0'
        option mode 'ap'
        option ssid '**OPS-17B**'
        option encryption 'psk2'
        option key ''
        option network 'lan70'

config wifi-iface 'wifinet7'
        option device 'radio1'
        option mode 'ap'
        option ssid '**HVAC-222**'
        option encryption 'psk2'
        option key ''
        option network 'lan20'

config wifi-iface 'wifinet8'
        option device 'radio1'
        option mode 'ap'
        option ssid '**SYS-MGMT-88E**'
        option encryption 'psk2'
        option key ''
        option network 'lan99'

root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '0'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option cachesize '1000'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option localservice '1'
        option ednspacket_max '1232'
        option noresolv '1'
        option port '5353'
        option dnsforwardmax '1024'
        list server '127.0.0.1#5335'
        list server '::1#5335'
        list server '1.1.1.1'
        list server '1.0.0.1'
        option logqueries '1'
        option logdhcp '1'
        list interface 'lan'
        list interface 'lan10'
        list interface 'lan20'
        list interface 'lan30'
        list interface 'lan50'
        list interface 'lan60'
        list interface 'lan70'
        list interface 'lan99'
        option interface_done '1'

config dhcp 'lan10'
        option interface 'lan10'
        option start '20'
        option limit '200'
        option leasetime '12h'
        list dhcp_option '6,10.137.228.1'

config dhcp 'lan20'
        option interface 'lan20'
        option start '20'
        option limit '200'
        option leasetime '12h'
        list dhcp_option '6,10.192.117.1'

config dhcp 'lan30'
        option interface 'lan30'
        option start '20'
        option limit '200'
        option leasetime '12h'
        list dhcp_option '6,10.251.36.1'

config dhcp 'lan60'
        option interface 'lan60'
        option start '20'
        option limit '200'
        option leasetime '12h'
        list dhcp_option '6,10.203.157.1'

config dhcp 'lan70'
        option interface 'lan70'
        option start '20'
        option limit '200'
        option leasetime '12h'
        list dhcp_option '6,10.42.219.1'

config dhcp 'lan99'
        option interface 'lan99'
        option start '20'
        option limit '200'
        option leasetime '12h'

config dhcp 'lan'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '24h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'
        list dhcp_option '6,10.65.82.1'
        list dhcp_option '3,10.65.82.1'
        list dns '::1'

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'
        option piofolder '/tmp/odhcpd-piofolder'

config dhcp 'wg_mullvad'
        option interface 'wg_mullvad'
        option ignore '1'

root@OpenWrt:~# cat /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'
        list network 'lan10'
        list network 'lan30'

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

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

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 zone
        option name 'momnet'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option mtu_fix '1'
        list network 'lan70'

config forwarding
        option src 'momnet'
        option dest 'wan'

config zone
        option name 'Quarantine'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option mtu_fix '1'
        list network 'lan60'

config forwarding
        option src 'Quarantine'
        option dest 'wan'

config zone
        option name 'vpnsendtotunnel'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        option mtu_fix '1'
        list network 'lan20'

config zone
        option name 'mgmt99'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'lan99'

config forwarding
        option src 'mgmt99'
        option dest 'wan'

config rule
        option name 'Allow-momnet-DNS'
        option src 'momnet'
        option proto 'tcp udp'
        option dest_port '53'
        option target 'ACCEPT'

config rule
        option name 'Allow-momnet-DHCP'
        option src 'momnet'
        option proto 'udp'
        option dest_port '67-68'
        option target 'ACCEPT'

config rule
        option name 'Allow-Quarantine-DNS'
        option src 'Quarantine'
        option proto 'tcp udp'
        option dest_port '53'
        option target 'ACCEPT'

config rule
        option name 'Allow-Quarantine-DHCP'
        option src 'Quarantine'
        option proto 'udp'
        option dest_port '67-68'
        option target 'ACCEPT'

config rule
        option name 'Allow-VPN20-DNS'
        option src 'vpnsendtotunnel'
        option proto 'tcp udp'
        option dest_port '53'
        option target 'ACCEPT'

config rule
        option name 'Allow-VPN20-DHCP'
        option src 'vpnsendtotunnel'
        option proto 'udp'
        option dest_port '67-68'
        option target 'ACCEPT'

config rule
        option name 'Allow-mgmt99-DNS'
        option src 'mgmt99'
        option proto 'tcp udp'
        option dest_port '53'
        option target 'ACCEPT'

config rule
        option name 'Allow-mgmt99-DHCP'
        option src 'mgmt99'
        option proto 'udp'
        option dest_port '67-68'
        option target 'ACCEPT'

config zone
        option name 'vpnzone'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wg_mullvad'

config forwarding
        option src 'vpnsendtotunnel'
        option dest 'vpnzone'

root@OpenWrt:~# kill -s USR1 dnsmasq ; sleep 1 ; logread -e dnsmasq | tail -10
ash: invalid number 'dnsmasq'
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option: 51 lease-time  12h
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option: 58 T1  5h35m3s
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option: 59 T2  10h5m3s
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option:  1 netmask  255.255.255.0
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option: 28 broadcast  10.192.117.255
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option:  3 router  10.192.117.1
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  3 option: 15 domain-name  lan
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size: 15 option: 12 hostname  LAPTOP-97CJ5VDB
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size: 22 option: 81 FQDN  03:ff:ff:4c:41:50:54:4f:50:2d:39:37:43:4a...
Sun Dec 14 12:04:17 2025 daemon.info dnsmasq-dhcp[1]: 4528247 sent size:  4 option:  6 dns-server  10.192.117.1

I made a mistake

killall -s USR1 dnsmasq ; sleep 1 ; logread -e dnsmasq | tail -10

(ie see server stats)

killall -s USR1 dnsmasq ; sleep 1 ; logread -e dnsmasq | tail -1
0
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: OpenWrt                        fd2c:2791:1840::1                        6F I   H                            /tmp/hosts/dhcp.cfg01411c
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-localhost.lan              ::1                                      6F I   H                            /etc/hosts
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-localhost                  ::1                                      6F I   H                            /etc/hosts
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: lan                                                                     !F  D      Mon Dec 15 00:59:42 2025
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: lan                                                                     !F I   H
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-loopback.lan               ::1                                      6F I   H                            /etc/hosts
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-allrouters.lan             ff02::2                                  6FRI   H                            /etc/hosts
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: LAPTOP-97CJ5VDB.lan            10.192.117.22                            4FR D      Mon Dec 15 00:59:42 2025
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-allnodes                   ff02::1                                  6F I   H                            /etc/hosts
Sun Dec 14 12:59:46 2025 daemon.info dnsmasq[1]: ip6-allrouters                 ff02::2                                  6F I   H                            /etc/hosts