Hi all home network administrators :) Haven’t posted anything here since June, when I told you about Gatekeeper 1.1.0. Back then it was a pretty bare-bones (and maybe slightly buggy) DNS + DHCP server with a web UI with a list of LAN clients. Back at 1.1.0 Gatekeeper didn’t even configure your LAN interface or set up NAT rules. It used to be something like dnsmasq
- but with a web UI.
I’ve been improving it for the past couple of months - simplified it a lot, fixed bugs, optimized internals, improved the looks & added a bunch of quality-of-life features. Now it’s a program that turns any linux machine into a home internet gateway. It’s closer to OpenWRT in single executable file.
One big thing that happend was that I’ve attempted to replace the ubiquitous nft
-based NAT (where the kernel processes the packets according to a rule-based script) with nfqueue
(where the kernel sends the packet to userspace so that it can be altered arbitrarily). I’ve expected this to be buggy & slow. Well, it was hell to implement but it turns out that it’s not slow at all. On the debug build my router can push 60GiB+ / second over TCP (over virtualized ethernet of course). And I’m not even using any io_uring
magic yet. Quite honestly I don’t even know how to explain it since it’s slightly above the peak DDR4 transfer rate (I’m running dual channel DDR4-3200). Maybe the pages are not flushed to RAM & are only exchanged through CPU caches? Anyway I’m pretty excited because userspace access to all traffic opens a lot of new possibilities…
The first thing is NAT. By default Linux only supports symmetric NAT, which is pretty secure but is also fairly hard for the peer-to-peer protocols to pierce. There are some patches that make Linux full-cone but they’re not, and are not expected to become a part of the mainline kernel (at least according to OpenWRT forums). Now, since we have access to every packet we can take care of this ourselves. We can create a couple hash tables to track connections, alter the source & destination IP, recomputing the checksums if necessary. Suddenly we can have full-cone NAT, on any linux machine, without patching the kernel! At runtime it’s not as configurable as netfilter + conntrack but it’s a whole lot simpler - since now we can use a general purpose programming language rather than netfilter rules.
Another cool feature that we can now have are truly realtime traffic graphs. Summary of each packet traversing the network boundary is immediately streamed to the connected web UIs over WebSocket. This is way faster than the alternatives based on reading some /
or //sys/
files every couple of seconds. Gatekeeper also aggregates the traffic from the last 24 hours between each pair of hosts into a histogram with 100ms resolution and allow clients to view it, scroll through it, compute stats, download as JSON or CSV. You can retroactively check which device talked with what IP, at what time with unprecedented resolution.
My next step is going to be capturing the traffic that goes through into a 5MB circular buffer (separate buffer for each LAN client) & downloading it as Wireshark-compatible pcap files. Computationally it’s almost free. IoT devices usually don’t transmit a lot of data. 5MB may actually cover months of traffic for the simpler ones. If any device is did anything weird, it will finally be possible to investigate it - even after it already happened.
Long-term Gatekeeper could do even more. For example offer assistance in setting up TLS MITM, perform some online grouping / analysis on the live traffic.
I still have some ground work to do - like automatically setting up Wireless LAN, bridgidng multiple interfaces into a single one and I think there may be a bug that causes crashes when checking GitHub for updates. But I wanted to share it sooner rather than later. I hope that despite its imperfections some of you will find it useful!
(I’ve had some issues with cross-instance posting. This is attempt #6)
Thank you for the feedback! I have to admit I wasn’t aware of how important port forwarding is. Stepping back I guess I’ll need a better way of gauging how important specific features are to people. I’ll have to think about this a little bit more…
Your question about security is something that I think about a lot. I don’t think of LAN & internet as significantly different in terms of security. I also worry about potentially malicious LAN devices attempting to exploit local DNS, DHCP or web UI. I’ve profesionally worked on anti-malware and I’ve seen malware preloaded on new phones by factory workers & resellers, suspiciously exploitable flaws in stock firmware (which I guess was a backdoor with plausible deniability), fake monetization SDKs that are actually botnets (so application developers have been unknowingly attaching bots to their apps). There is also the problem of somebody gaining the physical access to your LAN network (for example by connecting a prepared device to an ethernet port for a couple of seconds). While those things may seem far fetched and commercial routers ignore them, I’d like to do something better here.
In terms of preventing C++ footguns, I’m relying on compilation arguments (
-fstack-protector
,-D_FORTIFY_SOURCE=2
), safe abstractions (for examplestd::unique_ptr
,std::span
,std::array
…), readability (single-threaded, avoiding advanced primitives or external libraries) & patience (I think that time pressure is the biggest source of bugs).In terms of protocol level security, so far I’ve been able to secure the update path (so that MITM attackers can’t inject malicious code). The web UI is a big problem for me because to do any privileged operations I’ll have to authenticate the user first. Firstly I’m not exactly sure how to even do that. Password seems like the best option but I’m still trying to think of something better. There is this new WebAuthn thing which I’ll have to look into. Second issue with web UI is that I need to protect the authentication channel. This means that local web UI will need TLS. And this in turn means that I’ll have to somehow obtain a TLS cert somehow. Self-signed certs produce nasty security warnings. Obtaining one from LetsEncrypt seems easy - assuming the router has public IP (which may not always be the case). But even if I obtain a LetsEncrypt cert, any LAN device can do the same thing, so the whole TLS can still be MITM-ed. It would be really great if web browsers could “just establish encrypted channel” and not show any security warnings along the way…
thank you for the reply. All the stuff you wrote makes sense.
can you elaborate?
Yeah. LetsEncrypt usually verifies whether the client asking for a certificate owns the domain by sending a HTTP-based challenge. Gatekeeper could pass it by intercepting traffic on port 80. But any LAN device could also pass it by asking for port 80 to be temporarily forwarded. This means that LetsEncrypt TLS certificates are not worth much in LAN environment. Malicious IoT device could convince other LAN hosts that it owns the router IP be sending spoofed ARP announcements. Whenever any LAN device would try to visit Gatekeeper web UI, it would actually visit a fake web UI hosted by the malicious IoT device. The IoT device could then sniff the administrator password and perform privileged actions in the real web UI.
interesting. This could all be solved if gatekeeper doesn’t allow port redirection on 80 unless explicitly configured by the administrator, right?
Oh, yeah that would make sense. I think that would solve the whole security aspect :)