Avoiding DNS leaks with AdGuard Home and VPN provider

I'm looking for advice on avoiding DNS 'leaks' with AdGuard Home when connected to my VPN provider.

Here are the relevant portions of my network config:

config interface 'lan'
        option device 'br-lan.10'
        option proto 'static'
        option ipaddr '10.0.10.1'
        option netmask '255.255.255.0'

config interface 'vpn'
        option proto 'static'
        option device 'br-lan.20'
        option ipaddr '10.0.20.1'
        option netmask '255.255.255.0'

config interface 'provider'
        option proto 'wireguard'
        option private_key ''
        list addresses ''
        list addresses ''
        list dns '100.64.0.7'

The VPN provider's DNS server is private and is only accessible through the WG tunnel. Even though AGH is binded to all of the router's interfaces/IP addresses, it's not able to access it. I think it might be because it's not aware where it should go, as there's no specified route for that type of IP.

I've used PBR to force route clients connected to the 'vpn' interface to route to the VPN provider's gateway/WG tunnel, so if they had 100.64.0.7 set as their DNS server, they'd be able to reach it. However, I'm not sure how to do this in AGH's case. I tried creating a PBR policy for 127.0.0.1 to go to the provider's gateway/WG tunnel when attempting to reach the DNS server, as well as a static route for 100.64.0.7/32 to the provider's interface IP, but neither worked.

How would I solve this issue?

Newer pbr version in upstream repo supports "dns policies" which may help you.

1 Like

I currently have version 1.1.1-7 of pbr installed. If the upstream repository you're referring to is this, then it seems to be over a year behind.

Is there an ETA for version 1.1.6-16? If not, how can I install it manually?

No, I meant this.

Thank you. I've installed it, but I don't think it's applicable in my case. I only want to redirect AGH's queries to the the VPN gateway when the destined upstream DNS server matches the VPN's DNS server. So it would be a conditional rule, and there doesn't seem to be such an option for pbr's DNS policies.

Pretty much on the same boat.
AGH:53 --> vlan:5353 (dnsmasq) --> <vpn_dns_ip> is my setup. since the vpn_dns_ip is only available on WG tunnel, AGH times out
Fri Aug 23 10:29:17 2024 daemon.err AdGuardHome[22683]: 2024/08/23 14:29:17.456565 [error] dnsproxy: upstream 192.168.70.1:5353 failed to exchange ;www.google.com. IN A in 20.002375531s: exchanging with 192.168.70.1:5353 over udp: read udp 192.168.70.1:33344->192.168.70.1:5353: i/o timeout

coz there is no route defined to reach vpn_dns_ip on the tunnel. I tried port forwarding but didn't work

config redirect
	option dest 'wg_0'
	option target 'DNAT'
	option name 'wg_0'
	option src 'vpn'
	option src_dport '5353'
	option dest_ip '10.2.0.1'
	option family 'ipv4'
	list proto 'udp'
	option enabled '1'

If i replace src_dport with 53, dns query is hijacked from AGH and dnsmasq handles and It works as expected. Although this is not the solution I'm looking for.

Similar to OP, would need a way to tell AGH to connect to WG tunnel when forwarding the dns query to upstream resolver

Any suggestions or ideas?

Solved immediate issue by adding a static route

config route
	option interface 'wg_0'
	option target '10.2.0.1/32'
	option gateway '10.2.0.2'
	option source '192.168.70.1'

But I have 2 WG tunnels connecting to different public endpoints. However their private gateways are the same 10.2.0.1. Adding another static route such as above with appropriate interface, overrides somehow and causes DNS leak on the overridden route/interface

1 Like

With PBR you can set the interface to be used (which of course you can also set with a static route) and it has the ability to redirect DNS per client

Do you have an example of to set interface using static route. I added source info in LUCI and here is the equivalent config in /etc/config/network

config route
	option interface 'wg_0'
	option target '10.2.0.1/32'
	option gateway '10.2.0.2'
	option source '192.168.60.1'

config route
	option interface 'wg_1'
	option target '10.2.0.1/32'
	option gateway '10.2.0.2'
	option source '192.168.70.1'

config route
	option interface 'wg_2'
	option target '10.128.0.1/32'
	option gateway '10.129.85.17'
	option source '192.168.50.1

with this config ip route show only shows one route for 10.2.0.1 -> 10.2.0.2 although src is different as in the config

10.2.0.1 via 10.2.0.2 dev wg_1 proto static src 192.168.70.1
10.128.0.1 via 10.129.85.17 dev wg_2 proto static src 192.168.50.1

Tried adding new route with same private ip and gateway but on a different interface and ran into this error

root@router_main:/tmp# ip route add 10.2.0.1/32 via 10.2.0.2 dev wg_0 proto static src 192.168.60.1
RTNETLINK answers: File exists

Specify the necessary upstream (100.64.0.7) in AGH for all clients from the 10.0.20.1/24 range under Settings -> Client Settings -> Upstream DNS Servers.

Can confirm this is working.

Other parts of the setup:

Ah, this made me realize I had my static route attached to the wrong interface. AGH is now able to resolve to my provider's DNS server. Thanks!

I also managed to get it working with an additional WG tunnel despite it having the same private IP address for its DNS server (I'm not sure if the gateway portion you had was necessary):

/etc/config/network:

config route
        option interface 'wg1'
        option target '100.64.0.7/32'
        option source '10.0.20.1'

config route
        option interface 'wg2'
        option target '100.64.0.7/32'
        option source '10.0.21.1'

/etc/config/pbr:

config policy
        option name 'WG 1'
        option src_addr '10.0.20.0/24'
        option interface 'wg1'

config policy
        option name 'WG 2'
        option src_addr '10.0.21.0/24'
        option interface 'wg2'

I recommend reloading both the network and firewall services after applying these changes, as it wasn't working properly until I did.

Edit: Nevermind. I forgot I had a proxy setup on the browser I was testing with, so it mislead me to thinking it was working properly (I noticed when using another browser). Luckily, my provider offers several DNS servers, so I can avoid this issue for now.

I have the same setup, but it's sadly more of a workaround until AGH properly implements client groups (issue link). It prevents reverse resolving of client's IP addresses from working for the subnet specified, as manual client names overrides it.

1 Like

For once I felt happy and then I saw your edit :slight_smile:

I did try once again just to verify what you put it out there

/etc/config/network:

config route
	option interface 'wg_iot'
	option source '192.168.50.1'
	option target '10.128.0.1/32'
	option gateway '10.129.85.17'

config route
	option interface 'wg_usa'
	option source '192.168.60.1'
	option target '10.2.0.1/32'
	option gateway '10.2.0.2'

config route
	option interface 'wg_ind'
	option source '192.168.70.1'
	option target '10.2.0.1/32'
	option gateway '10.2.0.2'

/etc/config/pbr:

config policy
	option name 'iot'
	option src_addr '192.168.50.1/24'
	option interface 'wg_iot'

config policy
	option name 'usa'
	option src_addr '192.168.60.1/24'
	option interface 'wg_usa'

config policy
	option name 'ind'
	option src_addr '192.168.70.1/24'
	option interface 'wg_ind'

ip route show:

ROUTE FOR 70.1 IS ADDED. 60.1 IS NOT ADDED SINCE TARGET & GATEWAY IS SAME ALTHOUGH SOURCE AND INTERFACE IS DIFFERENT

10.2.0.1 via 10.2.0.2 dev wg_ind proto static src 192.168.70.1
10.128.0.1 via 10.129.85.17 dev wg_iot proto static src 192.168.50.1
192.168.50.0/24 dev br-lan.50 proto kernel scope link src 192.168.50.1
192.168.60.0/24 dev br-lan.60 proto kernel scope link src 192.168.60.1
192.168.70.0/24 dev br-lan.70 proto kernel scope link src 192.168.70.1

There is conflict in 2 networks since the DNS private ip for different public endpoints is the same. Due to IP conflict, DNS resolution on 60.1 shows DNS servers from 70.1 (essentially DNS leak since they connect to 2 different countries)

My another VPN has a different private DNS 10.128.0.1 and that works as expected.

At this point this is not a ADH issue. This is a routing issue I need to figure out. ADH forward DNS queries to my DNSmasq instance and that works perfectly. DNSmasq to private DNS on VPN tunnel is where I'm facing issue. I have internet connectivity but as i mentioned before there is DNS leak on one network

Yeah, sorry about that haha. I should've done more testing beforehand.

Since the main issue of this thread has been solved, I'm going to mark your second post as the solution. I think it'll cause this thread to close within 10 days if there's no reply, but it's probably best to have a separate thread for this routing issue we're having anyway.

1 Like

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