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
=========================

Saturday, June 20, 2026

KWin Window Tiling

I recently switched from GNOME desktop to KDE 6.7 (hands up hands down motion) and almost immediately ran into an issue with window tiling.

KDE's KWin has built in window tiling, where on GNOME I had to survive using the Gnome Tiling Assistant extension. Tiling Assistant was great, easy to setup and simple to configure, but I ran into some issues where the extension was not updated for new GNOME versions in time. Having native quarter tiling supported in KWin would have been a great benefit to me.

Except!

KWin's quadrant tiling was "real tiling" based, meaning windows snapped into corners and multiple windows were tiled as a "group" which meant they would resize together and always take up the full screen once you started tiling them. Many people enjoy this which is why it is the default. I do not.

I want my windows to size where I want them and be placed where I want them and then I want the window manager to leave them alone forever and never move or ask or mention them ever again.

Since I was unable to find a setting knob to "turn off the tiling but keep the tiling placement behavior", which I know, sounds so niche and yet this is exactly how my workflow has grown; I needed a way to have the behavior I was used to.

So, coming full circle, I wrote my own KWin script (extension) because of course I did. It's a single file, written in Typescript, sets hotkeys by default to the way I do things on my desktop, and does absolutely nothing else.

--

Android stuff soon, I hope.

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
=========================

Friday, February 27, 2026

TetherFutureNet (dropping support for older Android N versions)

Future versions of TetherFuseNet will bring support for a brand new proxy engine backed by the powerful Netty library. The engine will be opt-in by default at first, only for the brave, but will eventually be made the default engine and then even later become the only engine.

The by-hand written proxy code is decent but struggling to adapt to the modern web with new clients and modern behaviors. Netty is a well supported, battle tested library that should better serve users.

The downside is that the latest versions of Netty ONLY supports Android API 26 and up (Oreo). There are <1% of pyamsoft users stuck on Android 7 and 7.1 (which are just about a decade old at this point), so while this change will largely not impact anyone, it will impact this sub-1-percent group. Sadly, the reality of technology is that the quick pace of the world around us requires the adoption of generally newer and newer technologies.

Going forward all pyamsoft Android applications will require a minimum Android version of Oreo (26), or higher if the required core functionality expects a newer API version. All existing users who are still on Android 7/7.1 can continue to use existing versions of applications, but they can not be supported moving forward.

========================
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
=========================