Stupid Firewall Tricks
I make a lot of technical decisions based on a simple process where I learn about a thing and go, “Oh. Oh, no. Not that.” Then I have to figure out what not-that thing to use instead. Lather, rinse, repeat.
So, for example, my home firewall used to run pfSense. After their shenanigans with OPNsense.com I started to think that maybe I didn't want to be running pfSense anymore, but switching to something else would have taken time and effort so I just … never got around to it. Then, in a push for profits, pfSense owners Netgate also took a hostile stance towards users of the community edition, but my firewall still worked as it was, so I still didn't get around to changing it.
Then the FreeBSD WireGuard mess happened and I decided I needed to get away from any code managed by the people responsible. So now I run OPNsense. There's a common lineage (m0n0wall) and I was able to adapt my configuration without much trouble.
I'm not super happy about how FreeBSD's loose management let the WireGuard mess get as bad as it did, but migrating my stuff away from FreeBSD isn't high on my list of priorities. I'm not picking that battle any time soon. I only started using FreeBSD in the first place because I hated the way systemd was rolled out, but that's a different rant.
Anyway. My more recent “Oh. Oh, no. Not that” moment came when I discovered that our Chromecast had a trick up its sleeve.
For reasons of security as much as (perhaps even more than) general stubbornness, I run an instance of AdGuard Home for devices on the network that are impossible or impractical to configure to block their own ads. Any “smart” device on the network gets assigned to the AdGuard server instead of the main, unfiltered resolver running on my OPNsense firewall.
A weird unexpected side effect of blocking ads in this way was that several of the apps on our smart TV started crashing less. Since they were often crashing where ad breaks might exist (if we weren't paying for the ad-free versions, which we mostly are), my theory is that there's a “load the next thing” subroutine that can't reliably handle a transitory failure like a network blip at the wrong moment. But if the app can't connect to the ad server at all, even just for the “you don't need to display ads” ticket, then it grabs the whole program as one continuous segment. No more “load the next segment” subroutines, fewer crashes as a result. I wouldn't have predicted this, and for the most part we pay for service tiers without ads, but I'm not getting paid to deal with somebody else's bugs. Especially when the app loses our playback location when it crashes, resulting in several minutes of fussing just to get back to where we were before the app crashed.
Things were great when I set all this up, and then 48 hours later the Chromecast was showing ads again. It seems that Google anticipated people using things like AdGuard or a Pi-hole, and after some predetermined period of failure the Chromecast will just silently switch its own DNS and route around the blockage. It's smart, but I'm stubborn.
So I set up a couple new port forwarding rules on my firewall. Here's what I had to do:
Set up an alias for the AdGuard instance, with both its IPv4 and IPv6 addresses. Call it
AdGuard.Set up another alias for any streaming devices that I want to live in AdGuard jail. I started with IP addresses for this alias, but thanks to IPv6 I've now settled on using MAC addresses. Call this one
Streamers. Add the MAC addresses for every device you want to send to jail.Set up a Port Forward rule for traffic: a. On the
LANinterface; b.IPv4/IPv6; c.TCP/UDP; d. Source: theStreamersalias; e. Source port range:Any; f. Destination invert: checked (it's important that this be checked); g. Destination: theAdGuardalias; h. Destination port range: fromDNStoDNS; i: Redirect target IP: theAdGuardalias (again); j: Redirect target port:DNS.Copy that rule to a new rule, and change the port selections from DNS to the number
853, which is DNS over TLS.
Put together, these two rules ensure that any DNS traffic from any of the devices in that Streamers alias gets routed to my local AdGuard server.
For the Chromecast specifically, I added one more rule, just to be mean. That rule looks for traffic FROM the Chromecast specifically, TO a GoogleDNS alias (8.8.8.8, 8.8.4.4, 2001:4860:4860::8844, and 2001:4860:4860::8888), on port 443, which is DNS over HTTPS. That traffic, which would normally get routed as normal web requests, also gets forwarded to the AdGuard server. Luckily DNS over HTTPS doesn't validate the SSL certificate when querying.
So far the only device I've seen actual IPv6 traffic from is our new Apple TV, which also aggressively rotates its IPv6 addresses to try to foil tracking, but doing MAC-based filtering has worked exactly as intended. We have some IoT temperature monitors I should probably get the MAC addresses from to put them in jail as well, but I feel the workflow has been proven.
If you want me to use your software as designed, don't ever make me go, “Oh. Oh, no.”