Friday, 22 January 2016

Port forwarding with systemd

I wanted to run a daemon on a remote shell server and connect to it remotely.
Specifically it's a quassel core which I want to run inside the vpn.

Problem 1: The shell server, quite sensibly, doesn't allow external

Problem 2: The shell server, less sensibly, doesn't permit ssh local port
forwarding. I'll demonstrate why this doesn't make a great deal of sense on a
shell server (spoiler: you can do it anyway).

Assumption: When appropriately connected and authenticated, I can ssh into the
shell server without entering a password.

My first thought was obviously ssh port forwarding:
$ ssh -L 5555:localhost:5555 -Nf
But no:
channel 3: open failed: administratively prohibited: open failed
Boo! nc is available on the shell server, though, and if it wasn't I'd just
copy it there:
$ cat > ~/bin/ <<EOF
exec ssh -- nc localhost 5555
$ nc -l 5555 --keep-open -e ~/bin/
This runs a local nc process which acts like inetd. When it gets a connection
on 5555 it runs, which sshes to the shell server and runs nc
remotely to connect to my daemon on remote localhost port 5555. Now, I can
point my quassel client at localhost 5555 and it will create the ssh
connections automatically. Which is nice.

But wait! We can do better than that. I'd still need to remember to fire up nc
when I log in to my workstation, and that's way too much like hard work.
systemd to the rescue!

On an appropriately configured workstation (my Fedora 23 workstation does this
by default), systemd will run both a system daemon, and user daemons for any
users with active sessions. systemd also does the inetd thing, so I can just
write my own systemd unit for it:
$ mkdir -p ~/.config/systemd/user 
$ cat > ~/.config/systemd/user/quassel.socket <<EOF
Description=Proxy quassel connections


$ cat > ~/.config/systemd/user/quassel@.service <<EOF
Description=Proxy Quassel connections

ExecStart=-/usr/bin/ssh -- nc localhost 5555
$ systemd --user daemon-reload
$ systemd --user enable quassel.socket
$ systemd --user start quassel.socket
And that's it! Whenever I'm logged in to my workstation, connected to the vpn,
and appropriately authenticated, connections to localhost 5555 will be
automagically proxied over ssh to my quassel core daemon.