this post was submitted on 22 Oct 2023
440 points (98.0% liked)

Selfhosted

40487 readers
646 users here now

A place to share alternatives to popular online services that can be self-hosted without giving up privacy or locking you into a service you don't control.

Rules:

  1. Be civil: we're here to support and learn from one another. Insults won't be tolerated. Flame wars are frowned upon.

  2. No spam posting.

  3. Posts have to be centered around self-hosting. There are other communities for discussing hardware or home computing. If it's not obvious why your post topic revolves around selfhosting, please include details to make it clear.

  4. Don't duplicate the full text of your blog or github here. Just post the link for folks to click.

  5. Submission headline should match the article title (don’t cherry-pick information from the title to fit your agenda).

  6. No trolling.

Resources:

Any issues on the community? Report it using the report flag.

Questions? DM the mods!

founded 2 years ago
MODERATORS
 

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 /proc/ 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)

you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 7 points 1 year ago (7 children)

The readme is not so clear on this: does it also do port forwarding?

But seems pretty cool indeed 👍

[–] maf 8 points 1 year ago* (last edited 1 year ago) (6 children)

Unfortunately explicit, stable port redirections is something that is still missing. I'll have to implemnt them (with a proper UI) eventually because under the hood they are also a necessary building block for other features. At the moment there are only "ephemeral" port redirects which may be sufficient for you. They are created automatically when a LAN machine sends out a packet from some source port. That port is then implicitly forwarded back to that machine. This is actually a part of the "Full Cone NAT" thing.

This can be triggered manually for example with something like:

nc -p 80 1.2.3.4 1234 # send a dummy TCP packet from port 80

Ephemeral port redirections don't expire but can be taken over if another LAN host also uses the same source port for outgoing traffic. This may happen randomly because source ports are usually picked at random by the OS. Generally ports below ~32k should be fairly stable because Linux doesn't use those by default (I don't know about Windows). Redirecting ports below 1024 should be even more stable because they're reserved for specific well-known services.

[–] [email protected] 4 points 1 year ago (2 children)

What makes the port redirections difficult to implement in the code? I’m imagining the kernel has some way of handling this without too many external libraries but I’m not well-versed enough on this to know for sure.

[–] maf 6 points 1 year ago (1 children)

The relevant part of NAT is actually just those 20 lines.

The hardest part is actually the UI :P The difficulty in building nice UI comes from potential ports listening on the local WAN interface (for example if the machine is also running any HTTP or SSH servers). I'd like the user to see at a glance what ports are used for what (port used by a local service - what service is that?, ephemeral port redirection using the full cone nat table - where is it redirected?, any symmetric nat connections together with their last activity / timeouts / traffic summary). Ideally the same interface should also allow the user to create new redirects.

[–] [email protected] 3 points 1 year ago

I love what you did, especially the c++.

Using a unifi right now but this is the perfect replacement, especially since it's programmable, just put a few nic ports on a vm and let it run.

Just beautiful.

load more comments (3 replies)
load more comments (3 replies)