SSH is an awesome protocol and it can do a lot of things.
I found out that OpenSSH has native TUN device support.
Unfortunately I was not able to set this up properly.
On my Linux boxes this failed with interesting errors.
I ended up using strace
to find out that there is some permission idiosyncracy.
As I love using pipes in my terminal, I had an idea.
What about using socat
and piping IP traffic through the SSH tunnel?
tldr; it works.
$ sudo socat TUN:192.168.255.1/24,up EXEC:'ssh -l root HOST "socat TUN:192.168.255.2/24,up"'
Let’s break this monster down.
socat
allocates two entities and connects them via a bidirectional channel (e.g. two pipes for stdin and stdout respectively).
Let’s have a look at the “ADDRESS TYPES” section in the manpage here: socat(1)
.
Any of these address types can be used.
So let’s create a TCP listener and print everything to the terminal.
$ socat TCP-LISTEN:1234 -
This command creates a TCP listener at port 1234 and connects it to stdin/stdout of the socat process.
Eventually, this is a stupid replacement of nc -l -p 1234
.
One step further, socat
enables creating arbitrary processes and piping data into them.
With the TCP listener example we can pipe data from the network in a subprocess like grep
1.
$ socat -u TCP-LISTEN:1234 EXEC:'grep foo' &
$ echo "foobar" | nc 127.0.0.1 1234
The VPN stuff works like the very same. So, let’s start slowly2:
$ sudo socat TUN:192.168.255.1/24,up - | hexdump
This command allocates a TUN device, assings the ip address 192.168.255.1
, sets the device into the up
state (= enables it), and relays everything to the terminal into hexdump
.
When you ping the subnet via ping 192.168.255.2
then the IP packets show up.
So now, let’s send this data over an SSH tunnel.
ssh
is awesome as it provides a bidirectional connection (via two pipes) to a remote process.
Everything which is written to ssh
’s stdin is written to the remote process’ stdin tunneled via the SSH connection!
Well, let’s spawn a socat
an the remote side as well:
$ sudo socat TUN:192.168.255.1/24,up EXEC:'ssh -l root HOST "socat TUN:192.168.255.2/24,up -"'
The right argument (EXEC:"…"
) spaws ssh
logs into HOST
and starts a socat
which is connected to a tunnel device.
The remote socat
needs to write everything to -
(stdio) because -
is connected to the SSH tunnel.
It works!
The only problem left is that root
is needed on both sides.
But this can be solved somehow…