Netns socat Trick

2019/05/16

I mostly use this blog for theories, ideas, and think-pieces. But I figure I’ll return to the roots of blogging, and take the opportunity to explain a solution to a technical problem I encountered.

The Problem

I have a home lab server I built out old gaming PC. I haven’t done anything with its mediocre graphics card (so no exciting machine learning stuff). I’ve used it as a file server and a render box (blender’s CPU rendering only), but I’ve also used it as a VPN client. After failing on my own1, I ended up using the excellent namespaced-openvpn to set up a Linux net namespace whose only external connection is through the VPN, and which fails closed should the VPN be interrupted. This makes using applications of any sort (including console applications and daemons) very easy, especially compared to other less robust solutions rooted in syscall interception, or similar. It’s frequently easier to work with the kernel than against it.

User interaction with the net namespaces is pretty easy:

ip netns exec vpn bash

This launches a root bash shell in the namespace. Any child processes are also launched in the namespace as well. This namespace technology is part of the collection of technologies that make containers possible, and namespaced-openvpn implies that it would be possible to isolate the VPN user further, configuring an entire container to access the outside world exclusively through the VPN. This is interesting, particularly if it could be extended to Tor, rather than just a VPN, but that’s a project for another time.

However, I wanted to be able to run servers inside the namespace. I wanted the server to have a VPN only view of the world, but be accessible normally (on LAN, etc.). This is prevented by normal usage of network namespaces. Services that listen in the namespace simply don’t listen on open external ports. Search around I found a solution that involved even more virtual network configuration, but I mostly have that handled by namespaced-openvpn, and messing with configuration I don’t really understand is a great way to open myself up to security holes.

The Solution

The solution is socat, the Multipurpose Relay. socat takes 2 streams of any sort and connects them. It has a number of useful adaptors that let you read, listen, connect to, etc. 2 things, and then feed bytes between them. You can use a command like

socat file:~/.profile STDOUT

To print a file to standard out (replicating the normal cat) program, but you can also use it as a make-shift reverse proxy. If you have a local service running on port 3000, you can “re-listen” it and proxy it over a UNIX domain socket with this command

socat UNIX-LISTEN:/tmp/socat.sock,fork tcp:127.0.0.1:3000

This instructs socat to listen on a UNIX socket, and upon receiving a connection, to in turn connect to 127.0.0.1:3000 over TCP. Of particular note is the ,fork after the UNIX socket. This tells socat to fork a process for each connection to the socket, and to continue listening. By default, socat will accept one connection, do its proxying, and then close, refusing other connections. This behavior is undesirable for this purpose as I’m intending this server for long term use, and it’s web server anyway, and rarey does a web application need only 1 request: additional assets are usually required, not to mention the continued interaction.

This proxy command is run inside the namespace so it has access to the server. However, filesystems and UNIX domain sockets aren’t namespaced, so we can run the following command outside the namespace:

socat TCP-LISTEN:3003,fork UNIX:/tmp/socat.sock

I chose to listen on :3003 because I used 3000-3002 testing, and for some reason I couldn’t listen on them again. I assume they got released pretty quickly, but I’m pretty impatient. This is just like the last command, but the inverse. It listens on TCP, forks those connections, and proxies them to the socket. This works perfectly. It handles multiple connections (although not efficiently: process-per-connection should absolutely be avoided in production HTTP contexts). It’s pretty stable. It’s transparent. And it’s easy!

socat is an incredibly flexible tool, and this is just one of its many uses. It’s jam packed full of features, and I highly recommend its man page, this document of examples, and this basic introduction.


  1. There are a lot of important details rooted in the internals of Linux virtual networking that are easy to miss and compromise your security. ↩︎


linux