Automating SSH tunnels

Or, how I managed to update my parents’ home router using a mess of SSH tunnels.

I originally had an Idea some time ago when I moved flat and the new router would not allow to setup DHCP reservations nor port forwarding.. I figured instead of having the router manage these, I could punch a hole through the firewall from the inside and use an internet host + SSH tunnels to gain access into my home network.

More recently, my parents ISP updated their router and I wanted to make some changes to the configuration.. which I can usually only do when I visit them once or twice a year. Typically these routers also seem to lose their configuration every now and then after a thunderstorm, so I couldn’t really rely on their capability to hold on to it either.. Of course, getting family members to understand anything of making changes to the router is a no-go.

Port forwards

Normally, if I were to set up port forwarding on the router with an external port 8022 redirected to remotehost:22, then I can simply ssh to the router’s external-ip:8022 to access my machine.

Given we don’t have that mapping in place, we start off kind of bad.

What do

Two thoughts come to mind:

  1. SSH tunnels
  2. Puppet

Ever since learning about Puppet I grew quite fond of its capabilities and quickly setup a small infrastructure to manage our homeserver and a handful of Raspberry Pi’s. I’m going to take advantage of the fact that I already have it setup to run some commands “remotely”.

If you don’t have any remote management capabilities, I’m afraid it might be a bit more complicated to get started..

SSH tunneling

So the first step is to locally attempt to create a tunnel with the internet host. We want to open a port on the internet host (I choose 8022) that, when connected to, will in fact be connecting to my local server’s SSH port (22)

Proof of concept (run this on home machine):

/usr/bin/ssh -fnNT -R 8022:localhost:22 user@internethost

I’ll leave it to explainshell.com to.. explain the shell arguments.

With that, on the internet host I was able to do “ssh localhost -oPort=8022” and receive the prompt for my home machine!

However, this did not work remotely using “ssh internethost -oPort=8022

I had to update the “/etc/ssh/sshd_config” on the internet host with the following line:

GatewayPorts yes

See here for more: http://www.snailbook.com/faq/gatewayports.auto.html

Additionally, you might encounter connection timeouts and the tunnel drops. In which case you’ll probably have to add one of these two configurations:

# Server side; sshd_config
ClientAliveInterval 60
ClientAliveCountMax 2

# Client side, in ~/.ssh/config
Host internethost
 ServerAliveInterval 60

Restart the ssh process and tada! I’m now able to ssh into my home machine, from anywhere! And without having to think about static IPs, port forwardings, dynamic host names, etc.

ssh user@internethost -oPort=8022

At this stage, this is our access:

I then added that into the Puppet manifest, which although won’t restore the connection instantaneously in case of dropouts, should at least resume every time the agent runs (30 mins)

exec {
  'ssh_tunnel':
    command => '/usr/bin/ssh -fnNT -R 50014:localhost:22 user@internethost',
    unless => '/bin/ps -ef | /bin/grep -v grep | /bin/grep "ssh -fnNT"',
    user => 'johann',
    ;
}

Redirecting to a different host

So now the remote host has picked up the configuration change, we have access to the remotehost through the tunnel and it should be a bit quicker to do some testing. The aim now is to open another port on the internethost that will redirect to the remoterouter’s web port.

You might have noticed in the commands above we were using “localhost” to redirect requests to the local SSH port. By changing this to the internal IP of our remote router, we can redirect traffic to it’s web management interface.

ssh -fnNT -R 8080:192.168.1.1:80 user@internethost

And thus the final setup:

Now, I can remotely manage the remote router by visiting http://internethost:8080 in my web browser.

Keeping the tunnels running

I made a short script that I put to run in a crontab every few minutes:

$ crontab -l | grep Tunnel
*/4 * * * * /home/johann/tools/startTunnel.sh 8022

$ cat tools/startTunnel.sh
#! /bin/bash
port=$1
pgrep -f "ssh -fnNT" >/dev/null || /usr/bin/ssh -fnNT -R ${port}:localhost:22 johann@internethost
This entry was posted in Linux. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.