Userspace networking is a very useful technique to provide networking capabilities to your software without the need of special privileges.
Fly uses this for their cli tool so customers can connect to their infrastructure, essentially creating a wireguard connection against their resources on the spot. Tailscale also uses it to connect devices to tailnets – by the default you need root privileges.
I was always fascinated to understand how it worked so here is how I think it works. I will use tailscale in my examples.
When you want to encrypt network traffic, you typically use a TUN/TAP device provided by the operating system. At a high level, here’s how (I think) it works: When applications send data over the network via sockets, the data follows the OS networking stack, which adds the necessary headers. If the destination IP address falls within the subnet managed by your TUN device, the kernel redirects that packet to the userland application controlling the TUN device (e.g., tailscaled).
This userland application then processes the packet however needed - in Tailscale’s case, typically encrypting and sending it over an established WireGuard connection. For incoming traffic, packets reaching the network interface are processed by the device driver and move up the network stack. The kernel delivers these packets to tailscaled, which decrypts them and reinjects them into the network stack for delivery to the appropriate application.
But creating a TUN device requires root privileges. This is where userspace networking becomes valuable. Tailscale’s binary includes a complete userspace TCP/IP stack from gVisor. When userspace networking is enabled, you’re still conceptually creating a TUN device, but at the userspace level - application network calls are intercepted and handled by gVisor’s netstack TCP/IP stack instead of being passed to the kernel.
The payload gets processed entirely in userspace. When Tailscale receives the resulting IP or UDP packet, it encapsulates and sends it over another socket through the WireGuard connection. This packet then flows through the kernel’s TCP stack before being transmitted.
This approach lets you join a device to a Tailscale network (a “tailnet”) without root access. With one limitation: other processes on that machine cannot send data to the tailnet. To overcome this, you can use Tailscale’s SOCKS5 proxy feature with the –socks5-server flag.
This capability is truly mind-blowing. It’s how Tailscale can run in browsers 🤯, which lack traditional socket APIs and rely on technologies like WebSockets for networking. One Tailscale engineer (Brad) has created a demonstration of this concept. His implementation (from my understanding) tunnels WireGuard UDP packets over WebSockets, using Tailscale’s relay servers (DERP) which “talk” websockets.