Wireguard PBR DNS Leak

I am trying to fix a Wireguard DNS leak in my setup.
I have wireguard server and wireguard client (connecting to mullvad)
I also used pbr to route all traffic from wgserver to wgclient
That all works fine, however when connected to wgserver i want to use mullvad DNS, but i can't figure out how to do it, https://mullvad.net/en/check always shows dns leak

I tried a few things i could find, any similar topic here didn't help
I tried some forwarding rules in firewall and pbr, but it doesn't work

Edit:
As a temporary workaround, I added static route for mullvad dns ip, to always go through wgclient, and added it to dns forwardings. This way i am always using mullvad dns, not ideal but better then using other dns while connected to vpn.
I would still like to find a solution where "lan" interface uses cloudflare (or any other public dns), and wgclient uses mullvad internal dns

Here is my config:

network
package 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 'fdc1:ca56:8966::/48'
	option packet_steering '1'

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

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

config interface 'wan'
	option device 'eth1'
	option proto 'dhcp'
	option peerdns '0'
	list dns '1.1.1.1'
	list dns '1.0.0.1'

config interface 'wan6'
	option device 'eth1'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'
	option peerdns '0'
	list dns '2606:4700:4700::1111'
	list dns '2606:4700:4700::1001'

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

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

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

config bridge-vlan
	option device 'br-lan'
	option vlan '4'
	list ports 'eth0:t'

config bridge-vlan
	option device 'br-lan'
	option vlan '99'
	list ports 'eth0:u*'

config bridge-vlan
	option device 'br-lan'
	option vlan '5'
	list ports 'eth0:t'

config interface 'guest'
	option proto 'static'
	option device 'br-lan.4'
	option ipaddr '10.0.4.1'
	option netmask '255.255.255.0'

config interface 'iot'
	option proto 'static'
	option device 'br-lan.5'
	option ipaddr '10.0.5.1'
	option netmask '255.255.255.0'

config interface 'wgserver'
	option proto 'wireguard'
	option private_key 'removed'
	list addresses '10.0.10.1/24'
	option listen_port '61820'

config wireguard_wgserver
	option description 'laptop'
	option public_key 'removed'
	list allowed_ips '10.0.10.2/32'
	option route_allowed_ips '1'

config interface 'wgclient'
	option proto 'wireguard'
	option private_key 'removed'
	list addresses '10.64.222.204/32'
	list dns '100.64.0.23'

config wireguard_wgclient
	option description 'mullvad'
	option public_key 'removed'
	option endpoint_host '185.213.155.73'
	option endpoint_port '51820'
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::0/0'

dhcp
package dhcp

config dnsmasq
	option domainneeded '1'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	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 localuse '1'
	option noresolv '1'
	list server '1.1.1.1'
	list server '1.0.0.1'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv4 'server'
	option dhcpv6 'server'
	option ra 'server'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'

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'

config dhcp 'guest'
	option interface 'guest'
	option start '100'
	option limit '150'
	option leasetime '12h'

config dhcp 'iot'
	option interface 'iot'
	option start '100'
	option limit '150'
	option leasetime '12h'

firewall
package firewall

config defaults
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

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

config zone 'wan'
	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 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 redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'vpn'
	option src 'wan'
	option src_dport '51820'
	option dest_ip '10.0.1.1'
	option dest_port '51820'

config zone
	option name 'iot'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'iot'

config rule
	option name 'iot DNS'
	option src 'iot'
	option dest_port '53'
	option target 'ACCEPT'

config rule
	option name 'iot DHCP'
	option src 'iot'
	option dest_port '67-68'
	option target 'ACCEPT'

config zone
	option name 'guest'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'guest'

config forwarding
	option src 'guest'
	option dest 'wan'

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

config include 'pbr'
	option fw4_compatible '1'
	option type 'script'
	option path '/usr/share/pbr/pbr.firewall.include'

config rule
	option name 'Allow-WG-Inbound'
	list proto 'udp'
	option dest_port '61820'
	option target 'ACCEPT'
	option src '*'

config redirect
	option dest 'wgclient'
	option target 'DNAT'
	option name 'Intercept-DNS-WG'
	option src 'wgserver'
	option src_dport '53'
	option dest_ip '100.64.0.23'
	option dest_port '53'

config redirect
	option target 'DNAT'
	option name 'Intercept-DNS'
	option family 'any'
	option src 'lan'
	option src_dport '53'

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

config zone
	option name 'wgserver'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'wgserver'

config forwarding
	option src 'wgserver'
	option dest 'wgclient'

pbr
package pbr

config pbr 'config'
	option enabled '1'
	option verbosity '2'
	option strict_enforcement '1'
	option resolver_set 'none'
	option ipv6_enabled '0'
	list ignored_interface 'vpnserver'
	list ignored_interface 'wgserver'
	option boot_timeout '30'
	option rule_create_option 'add'
	option procd_reload_delay '1'
	option webui_show_ignore_target '0'
	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 policy
	option name 'Ignore Local Traffic'
	option interface 'ignore'
	option dest_addr '10.0.10.0/24'

config policy
	option src_addr '10.0.10.0/24'
	option interface 'wgclient'
	option name 'route wgserver to wgclient'

config policy
	option name 'forward dns'
	option dest_addr '100.64.0.23'
	option dest_port '53'
	option chain 'forward'
	option interface 'wgclient'
	option src_addr '10.0.10.0/24'
	option src_port '53'

You have configured unencrypted DNS to 1.1.1.1, via tunnel.

No? What do you mean exactly.
1.1.1.1 is for wan

No no no. It is upstream for dnsmasq, I suppose it should be something mullvad with 1.1.1.1 as exception for .pool.ntp.org and .openwrt.org and if anything is looked up by mullvad before own dns is accessible.

Go Luci/Network/DNS+DHCP/Forwards. Textbox prefill is self-explaining.

Add the Mullvad DNS server in the wireguard configuration of the devices connecting to the wireguard server.

My idea was to have that for wan, and then "override" it somehow for mullvad, but i guess that is not how it works
Whatever i put in DNS+DHCP/Forwards will be used for all, but i would like wgserver and lan to use different dns servers

I would like to avoid that, i want to disallow client to set their own dns (which i already have for lan)

I am not sure if you can avoid that. Wireguard doesn't advertise the DNS, so if you want the client to use the DNS of your choice, you'd need to configure it on the client. Otherwise the client will continue resolving using whatever DNS was configured before the VPN was established.

3 Likes

Is there no way to do it similarly how dns hijack works for lan. Intercept dns request on port 53 in the wgserver interface, and then forward it to mullvad dns?

Provided that the DNS packets traverse through the tunnel and they are not encrypted, you can hijack them.