Saturday, August 8, 2026

DNS Local Overrides in a VPN Tunnel

Just figured this out and figured I'd tell you.

Warning: it's super hacky.

I've got an OPNsense network running multiple VLANs. Many of them are not VPN'd but one is, let's call that VLAN the TunnelNet.

My setup is as follows: I've got my NormalNet on 192.168.1.0/24 and my TunnelNet on 192.168.20.0/24. I've got Unbound running on the OPNsense box with DoT to Cloudflare and DNS blocking via Hagezi lists. I've got some local DNS overrides setup so that going to `myhome.com` will redirect to a local machine running Home Assistant on the network at 192.168.1.10/32.

I wanted to be able to access `myhome.com` from both my NormalNet and my TunnelNet, while keeping the DNS sealed over the TunnelNet network to Mullvad. 

----

Following the "out of the box" DNSmasq and Unbound setup in the OPNsense documentation I was easily able to get myhome.come DNS overrides setup on NormalNet, but TunnelNet was always a struggle because of the following:

TunnelNet's upstream is Mullvad, and I want it to not leak DNS. If traffic ever reaches unbound to resolve the DNS overrides, when a non-override domain request comes in, Unbound will use the Cloudflare DoT to resolve the name, which would leak DNS. To avoid leaks, I had a firewall rule setup to Pass DNS traffic but force it onto the WG_Tunnel gateway, which would go directly to the Mullvad upstream and bypass my DNS override. This fixes the DNS leaks, but it prevents TunnelNet from accessing the DNS overrides.

The fix was largely as follows:

Assuming Unbound on 53 and DNSmasq on 5335, where DNSmasq holds the actual DNS overrides, and Unbound just forwards to DNSmasq when `myhome.com` comes in:

Add `Domains` to DNSmasq that capture "*" and route it to the mullvad server IP `100.64.0.7/32` on port `53`. This means that ANY DNS request that hits DNSmasq and is NOT handled by the `myhome.com` override will hit this rule and attempt to use the WG internal Mullvad DNS to lookup. Great!

Add a static route to System -> Routes that ensures that 100.64.0.7/32 resolves over the correct WG interface just incase (though this may not be needed but it should not hurt)

Add a NAT Destination redirect rule for:

When a packet on interface TunnelNet targets ! This_Firewall on DNS port 53 -> redirect it to This_Firewall port :5335
When a packet on interface TunnelNet targets This_Firewall on DNS port 53 -> also redirect it to This_Firewall port :5335

The firewall pass rule must be updated to NOT force the WG_Tunnel gateway, and should instead use the "system default" gateway, and should instead accept traffic on :5335: instead of DNS port :53


This means that ANY DNS request sent on the TunnelNet VLAN will be directly redirected to port :5335 where DNSmasq is running, and will completely skip Unbound. Requests for `myhome.com` will be resolved via DNS overrides to 192.168.1.10/32, otherwise it will be sent upstream via the `Domains` override to the Mullvad DNS server.

Packet -> TunnelNet -> DNS(port:53) ->rdr-> 127.0.0.1:5335 -> Firewall pass::
  -> myhome.com --> DNS direct override
  -> any other website --> Mullvad DNS upstream

This allows connections on TunnelNet to avoid DNS leaks but will still correctly DNS resolve myhome.com, and NormalNet connections will go over Unbound as usual, except when they are forwarded to DNSmasq for `myhome.com`, in which case they will never hit the DNSmasq `Domains` upstream hit since the local name will be immediately resolved. Keeps a clean NormalNet and TunnelNet separation, but still ensures both can resolve local DNS names.

----

The current edge cases are:

DNS blocklist used by NormalNet will not be able to be used by TunnelNet since DNSmasq does not support blocklists at this time, but most VPN providers will have their own DNS blocklists so that is not a huge deal.

DNS caching will be duplicated between Unbound and DNSmasq, but that will not be a huge issue for most simple home networks. Yes its a problem, but in day to day practice this does not impact the wife-approval-factor.

-----


This was super nerdy, but I hope it may help you, or future me set this up again.
I am sure there will one day be a cleaner "non DNS Domains hack" way to do this, but for now, this works, keeping everything in the OPNsense GUI configuration with no custom conf.d overrides, so it's good enough for me.

----

TetherFuseNet is coming along and the new engine will be default soon.

Stay tuned!



========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyamsoftapps@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my Facebook Page
Check out my code on GitHub
=========================