SSH through firewalls using a reverse SSH tunnel

There are many posts on the Internet with instructions to set up SSH tunnels. However, the tutorials I found described either ways to:

  • forward HTTP and other protocols from a firewalled machine through one that is not firewalled,
  • or forward ports on the inside of the firewall (that aren’t supposed to be accessible outside of it) through an SSH tunnel to allow access from outside of the firewall.

What I didn’t find, was instructions on using SSH tunnels to allow me to SSH from a non-firewalled machine to one that is behind a firewall and NAT.

The short solution is to run sshd on the firewalled machine, and use the second method to forward the ports on localhost to a remote machine.

To do this requires setting up a reverse SSH tunnel. In short, the firewalled machine will SSH to the non-firewalled machine, and expose a port on that machine that the non-firewalled machine can SSH to. SSH’ing to the new port will create an SSH connection to the firewalled machine’s SSHD.

In my particular case, the firewalled machine was running Windows, so Cygwin was used with OpenSSH. The non-firewalled machine was running Ubuntu 11.10 Oneiric Ocelot.

Detailed instructions follow:

Install SSH

First, install Cygwin on the firewalled machine. Cygwin can be downloaded from http://www.cygwin.com/. When installing Cygwin, it will ask what packages you want to install. You will need OpenSSH, which is not enabled by default. Navigate to the package (it’s under Net) or search for it, and click the text “skip” to change it to a version number. Then click next to continue the installation.

After installing Cygwin, you may want to add Cygwin’s bin directory to your PATH. The rest of the examples in this tutorial assume you have done so.

Configure SSHD

Next you will need to configure SSHD on the firewalled machine, and start it. From Cygwin’s bash command prompt, enter the following:

ssh-host-config -y
cygrunsrv -S sshd

I followed the instructions at Noah’s SSHD HowTo to do this step. That site also provides a fix for an error that you may get. I did not get the error initially, but I reinstalled Cygwin and it came up that time. The solution on that page worked for me.

Test SSH to localhost

To ensure that SSHD is up and running on the firewalled machine, ssh to localhost from the firewalled machine’s Cygwin bash:

ssh localhost

If SSHD is working, you will be able to connect to the firewalled machine’s SSHD from the firewalled machine.

Test SSH to the non-firewalled machine

To ensure that you can connect out from the firewalled machine to the non-firewalled machine, ssh to the non-firewalled machine’s external IP:

ssh nonfirewalledmachineuser@non.firewalled.machines.external.ip

You need to be able to ssh to the non-firewalled machine in order to set up the reverse tunnel.

Set up the reverse tunnel

To set up the tunnel itself, I followed the instructions on HowToForge’s Reverse SSH Tunneling article.

From the firewalled machine’s Cygwin bash prompt, run:

ssh -R 19999:localhost:22 nonfirewalledmachineuser@non.firewalled.machines.external.ip

Where 19999 is the port to set up on the non-firewalled machine, and 22 is the port on localhost to route the connection to. If the connection ever times out, the tunnel will be broken, so you need to keep the connection alive. You can run top to keep the connection alive.

Once that is connected, you can ssh to the firewalled machine from the non-firewalled machine by running:

ssh firewalledmachineuser@localhost -p 19999

Other SSH-based services like sshfs can also be used through the tunnel. You may also want to run SSH without any standard input or commands running:

ssh -nNT -R 19999:localhost:22 nonfirewalledmachineuser@non.firewalled.machines.external.ip

or if you want to run it in the background:

ssh -fnNT -R 19999:localhost:22 nonfirewalledmachineuser@non.firewalled.machines.external.ip

These two options seem to keep alive by themselves, but I am not sure if it is guaranteed that they will. There are various keep-alive tricks described in the comments of a blog post on The Mad Philosopher. My preferred solution is to put

ServerAliveInterval 60
ServerAliveCountMax 9999

into $HOME/.ssh/config.

About these ads
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s