Sharing a solution for DNS leak with AdGuard Home handling client requests + connecting to VPN client

Hello,

I've passed this discovery on to GL.iNet staff as well, but wanted to share here for visibility.

I am relatively new to the GL.iNet product line. I'm a fan. But nothing is perfect. :slightly_smiling_face:

Consider a scenario where AdGuard Home is toggled on to handle client requests directly:

This works very nicely for many use cases (though not without caveats or exceptions, such as disrupting VPN policies based on domain, which is made clear in the UI).

However, if one then connects a device to a VPN client, it causes DNS leaks. This is definitely not nice. It's a bug.

In such a scenario, instead of the DNS server(s) being from the VPN provider, they are from the DNS server(s) configured in AdGuard Home (Settings > DNS Settings > Upstream DNS servers and Settings > DNS Settings > Fallback DNS servers). This is obviously non-desirable.

After some digging, I found the problem: The order of port forwarding rules specified in LuCI (after logging into LuCI, go to Network > Firewall > Port Forwards).

By default, the port forwarding rules created by GL.iNet are in the order of:

  • Adguard home
  • Adguard home guest
  • dns for vpn
  • dns for vpn guest

However, these rules are processed in order, so all DNS requests – even when a client is connected to a VPN – end up getting forwarded to AdGuard Home. Hence the DNS leaks.

All I did was change the order to:

  • dns for vpn
  • dns for vpn guest
  • Adguard home
  • Adguard home guest

And violΓ ! No more DNS leaks.

I hope this helps.

3 Likes

Nice, thanks! I'll check it out.
Currently in my wireguard profile I set my VPNs DNS to the Router (AGH) and the Upstream DNS Server in AGH to my VPNs IP and it works with no leaks. No other Upstream DNS Servers and no Fallback DNS servers in AGH.
When creating the wireguard profile for the VPN I can chose: No blocking, malware blocking or malware, tracker and ad blocking. Currently I use it without blocking. I'll try a few different combinations with your solution and see if anything improves.

I suspect you might like what you find when you try out my solution. One of the reasons I like my solution is it is a "configure it once, and it just works" solution. In your solution, you'd probably need to change things if you connect to a different VPN server or location or if the IP address for the VPN otherwise changes. My solution avoids all of that. Additionally, with my solution, there's also no need for extra configuration of the VPN's DNS.

Good luck, and I hope it makes your life easier!

May I ask what you put in as upstream DNS server and fallback DNS server? I'm not really a pro when it comes to this stuff.

Also do we have any confirmation from gl-inet that this is on their "to fix" list?

Thanks

Thanks for sharing, it's a very interesting approach. But seems that starting from 4.8.0 things are changing, no more Port Forwards rules in luci by GL.iNet team, now a script handles it all: /etc/firewall.dns_order

Reversing those two lines does the same thing that Integritas explained before:
-A dns_dispatcher -j adg_redirect
-A dns_dispatcher -j policy_redirect

In my case I still needed a single device that goes through VPN but still by AGH's rules, iptables did the trick, I just added those 2 lines in Network > Firewall > Custom Rules:

iptables -t nat -A PREROUTING -p udp -m udp -s my_device_ip --dport 53 -j DNAT --to-destination router_ip:3053
iptables -t nat -A PREROUTING -p tcp -m tcp -s my_device_ip --dport 53 -j DNAT --to-destination rouer_ip:3053

Now all vpns use their own dns servers except rules I manually specify in iptables

1 Like

Sure! But rather than just telling you what I use, I want to emphasize there's not really a "this is definitively the best" or "this is definitively the worst" answer here. It's more about what you're trying to accomplish. AdGuard helpfully maintains a list of known DNS providers: Known DNS Providers | AdGuard DNS Knowledge Base, and their tabulation includes features of the different DNS providers (e.g., filtering, non-filtering, family, and so on). So, you might take a look at that and see what suits your fancy. I'm currently using Cloudflare and Google for my upstream servers and Quad9 and ControlD for fallback servers.

The only thing I'd say you should really consider is opting for some form of encrypted DNS, such as DNS over HTTPS (DoH) or DNS over TLS (DoT). There are pros and cons with respect to which type; some people get very passionate about this as well, but as with many things, the answer often sorta' ends up being "it depends". I favor DoH. If you want to read more, this is a good place to start: https://www.cloudflare.com/learning/dns/dns-over-tls/.

So, adding that all up: I use DoH servers from Cloudflare and Google for my upstream servers and DoH servers from Quad9 and ControlD for my fallback servers (and these are all listed in the URL I included above from AdGuard).

I hope this helps!

2 Likes

They wrote me back thanking me for contacting them, but they noted they would be delayed in replying more fully due to the May Day holiday. @root1 is suggesting there may be signs of them addressing this as part of 4.8.0. I've not looked at any of that myself yet. However, 4.8.0 is still in Beta, and it'll only be released for certain models initially. So, even if the 4.8.0 firmware does fix this, there's a question of when 4.8.0 will actually be promoted to a release candidate and then a stable firmware. I'll aim to update this thread once I hear back from GL.iNet more fully.

Interesting! I haven't looked at 4.8.0 myself yet. But as I mentioned in my reply to @genki, 4.8.0 is still in Beta, and it'll only be released for certain models initially. So, even if the 4.8.0 firmware does fix this, there's a question of when 4.8.0 will actually be promoted to a release candidate and then a stable firmware.

If I'm being more precise, I also had to do some additional configuration beyond what I posted in my original post, because I'm running VLANs, so I needed additional rules to cover the various VLANs I'm running. On that note, I was disappointed (despite the GL.iNet products I've purchased and used so far both being extremely good, and like I said, I'm a fan!) that the GL.iNet UI suggests any client connected to a VLAN is not connected to the router (i.e., all my clients are connected to a VLAN, so the UI for my router right now suggests I have 0 clients connected, even though all my clients are connected and running just fine). I've sent them a message about that as well.

4.8.0 didn't fix it, and tbh I think that's the way it's supposed to work(AGH then VPN then router), but in order to switch that, now we have to modify a script instead of the rules in luci.

About 4.8.0, I really like the VPN dashboard, it lets you use multiple VPN connections with customizable rules within the glinet GUI which could be very useful and practical.

VLANs are tricky, specially when using glinet firmware combined with openwrt 21.02, some models now support up to v24.10.0

Ah, I see. Perhaps I misunderstood what you were saying originally. So, to be clear, you're saying the current build of 4.8.0 doesn't actually introduce the fix I introduced here, but rather, introducing the fix I demonstrate here may become more complicated with 4.8.0. Right?

I'm hopeful the good folks at GL.iNet can implement the fix for everyone once they've had a chance to review my feedback (many of them are on holiday until the 5th of May from what I've heard). In their most recent correspondence to me, they said they'd likely respond within this thread (I made them aware I'd posted here as well). I did speak with someone who originally said the way it is right now is by design, but I think that's incorrect. Perhaps we were just crossing wires a bit in that communication / not communicating clearly with one another, but in the world of "features and bugs", there's no way anyone can convince me that an implementation that introduces DNS leaks is a feature. :slight_smile:

This sounds amazing! Extremely interested in this and grateful to see the GL.iNet team introducing this!

I agree, but what I'm asking for doesn't seem terribly complicated. I've started a new post about that if you're interested: GL.iNet UI shows no clients connected due to use of VLANs - #3 by Integritas.

I took a look at the discussion. What needs to be implemented is that AdGuard will be able to handle DNS for non-VPN traffic, while DNS for VPN traffic will be handled by the VPN itself.

Maybe you can try the following settings: Disable AdGuard Home Handle Client Requests.


Disable Custem DNS to Override VPN DNS.

Hope it helps.

Maybe you can try upgrading to v4.8, we have made some new adjustments to it.

Thanks

Hi @teleney! Thanks so much for your reply.

Unfortunately, what you've suggested doesn't resolve the issue at hand. It's more of a workaround than a solution. Allow me to explain.

"Allow Custom DNS to Override VPN DNS" (your second screenshot) was never toggled on for me at any point in the lifetime of me owning the routers I have from GL.iNet. So, we can eliminate that from further consideration here.

Yes, toggling off "AdGuard Home Handle Client Requests" in the GL.iNet UI (as shown in your first screenshot) avoids DNS leaks, but that's a workaround rather than a resolution to the problem I've raised. The approach you suggest completely removes key functionality within AdGuard that's enabled when you have that option toggled on. For example, with that option toggled off, I lose both (1) the ability to have client-specific rules configured within AdGuard and (2) client-specific query logging, because toggling off "AdGuard Home Handle Client Requests" results in everything being resolved through "localhost" with a static IP address instead of the actual client IP addresses. (1) and (2) are huge parts of AdGuard's functionality, particularly (1). Moreover, in my view, it is a serious issue that users will experience DNS leaks (perhaps unbeknownst to them) if that option is turned on and they also try to connect devices to a VPN client on the router. In the world of "features and bugs", that's definitely a bug.

To draw an analogy, the problem I've identified above is kind of like me pointing out a problem with my company's cars that are intended for employee use, along with a solution to fix that problem. Your proposed workaround (of toggling off "AdGuard Home Handle Client Requests") is kind of like telling me my employees can still get to their final destinations by taking a bus, train, taxi, etc. Yes, the workaround sort of accomplishes the end goal (i.e., yes, I can still achieve some degree of ad blocking / control over DNS resolution), but it doesn't fix the problem with my company's cars directly (i.e., it doesn't resolve the DNS leak issue I've found). Moreover, using the workaround also results in loss of insight and control along the way to that final destination: I'm now reliant on the singular navigation system of the bus, train, taxi, etc. rather than my the GPS within each of the company cars (i.e., I can only set global rules to be resolved through the "localhost" custom IP that handles all traffic being processed by AdGuard), and I thus also lose the ability customize the route or allow or disallow certain music while driving if desired depending on who's driving the car, where they're trying to go, etc. (inability to have client-specific DNS rules). It also severely limits my ability to monitor things along the way (inability to have client-specific query logging).

However, the solution I present in my original post resolves this. It achieves exactly what you say

while still allowing that fuller functionality of AdGuard Home. I really hope GL.iNet will consider this more fully. I'm happy to partner with you all in talking through things more if you'd like.

Lastly, with respect to your comment

I'd be happy to do this if I had more of a spare router to tinker with, but my routers from you all right now are in such regular use (and need continual reliability and stability in their deployments) that I cannot really play around much with beta firmware on them. However, I did sign up to be a beta tester of the Flint 3, so if I'm selected as a beta tester for Flint 3, I would also then have the opportunity to beta test the 4.8 firmware!

Thanks for everything you and everyone else at GL.iNet does! Your commitment to your customers really shows, and I really appreciate it!

I'm really new to all this but in my mind it should be like that the traffic should be handled by AGH first and then sent through the VPN?! So first filtering by AGH then a secure connection via VPN. Isn't it how it should be?

Like I previously posted I set my VPNs DNS to AGH and AGHs upstream DNS server to the VPN and it seems like AGH is working, VPN too and I don't have any DNS leaks. Both options you showed are also disabled.

I tried your solution but unfortunately AGH is not working anymore. I set up everything as you instructed and while I don't have DNS leaks, the AGH query log doesn't show entries. Of course I tried it with a VPN profile where I didn't change the DNS server. As soon as I end the VPN connection AGH starts working again.

When set it up the way I did before I can't see the different clients as all traffic comes from "localhost" but besides that everything seems to work. I now did it without changing the port rules and it seems like they don't make a difference – everything's working as before I had the same settings without the changed port rules. I even tried leaving the "AdGuard Home Handle Clients Request" option on but it changed nothing.

Any ideas? Maybe I need to change the proxy mode in the VPN dashboard?

This experience is completely expected with the solution I posted earlier. My solution aims to use the VPN DNS when the VPN is active and AdGuard Home DNS when VPN is not active. This places information security, control, privacy, and relative ease of configuration as the the items to ensure and optimize above all else (including ad blocking). So, "AGH is not working anymore" and "the AGH query log doesn't show entries" is completely expected when connected to a VPN client and using my solution, because the AdGuard Home DNS functionality is completely out of the loop when connected to a VPN client in my earlier solution. I thought this was apparent in my post, particularly via my description of the port forwarding rules being processed in order and my swap of the order, but I apologize if that wasn't clear enough. :slight_smile:

If this is how you favor doing it, that is totally fine! But realize you lose a lot of additional functionality within AdGuard Home if you do it this way. See my reply to teleney for details (e.g., you cannot control things by individual clients or by CIDR and you cannot see client-specific logs; I've included a snippet of my reply to @teleney below). But as with most things in life and as alluded to above, it's about tradeoffs and what value functions you're trying to optimize. :slight_smile:

My original post is specifically centered on when users are using AdGuard Home to handle client requests directly. So, what seems to be your desired use doesn't apply to what I'm raising with GL.iNet and sharing with others who want to use AdGuard Home to handle client requests directly. That's not to say you can't still raise your use case in this thread, just trying to draw a clear distinction / point out the differences to avoid any confusion. On that note, in your reply to teleney, you state:

If you want to: (1) maintain AdGuard Home filtering (2) while using a VPN client and (3) while being able to tap into that additional functionality of AdGuard Home I mention above where AdGuard Home handles client requests directly, you would tweak my solution a bit:

  1. Leave the port forwarding rules (in Network > Firewall > Port Forwards) alone / leave them as set by GL.iNet in their default setup. No changes in LuCi!
  2. Toggle on AdGuard Home to handle client requests directly
  3. Use the upstream server specification within AdGuard Home to specify the DNS of your VPN provider. Note you can do this in more than one way, depending on what you're trying to accomplish. For global, always-on VPN, go to 4. For client-specific VPN (whether one client, a few, or anything coming from within a specified CIDR or multiple CIDRs), go to 5.
  4. Global, always-on VPN: If you're planning to route all traffic through your VPN provider and leave it on all the time, then:
    • Enter your VPN's DNS in Settings > DNS Settings > Upstream DNS Servers
    • Leave Settings > DNS Settings > Fallback DNS servers blank
  5. Client-specific VPN (whether one client, a few, or anything coming from within a specified CIDR or multiple CIDRs): If you're planning on routing traffic from 1 or more clients through your VPN, then:
    • Configure whatever you want to configure for upstream DNS servers globally in Settings > DNS Settings > Upstream DNS Servers (e.g., Google, Quad9, Cloudflare, etc.). These will be active when not connected to your VPN.
    • Configure a "Persistent client" record via Settings > Client Settings and clicking the Add Client button.
      • Enter a name for the client or client group in the box prompting for such.
      • Enter an appropriate identifier (e.g., the relevant IP address(es) of the client(s), or the CIDR(s) if defining a range or ranges).
      • Click the Save button (which will save the settings and close the window).
      • (The above is really just to facilitate the next step while still using the globally-defined rules when not connected to the VPN. If you'd rather wait to do this until the time of connecting to the VPN, you don't strictly have to do this ahead of time.)
    • When you want to connect that client/those clients to the VPN, edit that "Persistent client" record created in the previous step (or create a new one following the directions in the previous step if you didn't create one ahead of time).
      • Now, instead of using the globally-defined upstream DNS servers, you'll edit the upstream DNS server to point to the VPN's DNS.
      • Note you may need to tweak the IP address specification if the IP address(es) for the client(s) in question changed for some reason between originally creation of the "Persistent client" record and when you edit it to connect to the VPN.
    • When you're done with the VPN connection, delete the VPN DNS specified as the upstream DNS server in the "Persistent client" record. This will result in the client(s) specified by that record starting to use the globally-defined DNS servers again.

I hope this helps!

Hi,
You are absolutely right.

In v4.7, due to the overall architecture, this function was not implemented.
In v4.8, we have redesigned DNS distribution. Although the current implementation is somewhat different from what you said, I will try to make some modifications.

Thanks for your valuable suggestions.

1 Like

Yes, you are right.
It is just that when you disable AdGuard Home Handle Client Requests, DNS requests will be forwarded to ADH by the local dnsmasq.

Your settings seem to let all DNS requests be filtered by ADH and use VPN to establish the connection.

Wonderful, thank you! It may also be of interest to you and others working on this to review part my most recent response to @lirotia where I delineate a method to (1) maintain AdGuard Home filtering (2) while using a VPN client and (3) while being able to tap into that additional functionality of AdGuard Home I mention above where AdGuard Home handles client requests directly