Tell me more ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

As I understand this, firewalls (assuming default settings) deny all incoming traffic that has no prior corresponding outgoing traffic.

Based on Reversing an ssh connection and SSH Tunneling Made Easy, reverse SSH tunneling can be used to get around pesky firewall restrictions.

I would like to execute shell commands on a remote machine. The remote machine has its own firewall and is behind an additional firewall (router). It has an IP address like 192.168.1.126 (or something similar). I am not behind a firewall and I know the remote machine's IP address as seen from the Internet (not the 192.168.... address). Additionally, I can ask someone to execute ssh (something) as root on the remote machine first.

Could anyone explain me, step by step, how reverse SSH tunneling works to get around the firewalls (local and remote machines' firewalls and the additional firewall between them)?
What is the role of the switches (-R, -f, -L, -N)?

share|improve this question

2 Answers

up vote 19 down vote accepted

I love explaining this kind of thing through visualization. :-)

Think of your SSH connections as tubes. Big tubes. Normally, you'll reach through these tubes to run a shell on a remote computer. The shell runs in a virtual terminal (tty). But you know this part already.

Think of your tunnel as a tube within a tube. You still have the big SSH connection, but the -L or -R option lets you set up a smaller tube inside it.

Every tube has a beginning and an end. The big tube, your SSH connection, started with your SSH client and ends up at the SSH server you connected to. All the smaller tubes have the same endpoints, except that the role of "start" or "end" is determined by whether you used -L or -R (respectively) to create them.

(You haven't said, but I'm going to assume that the "remote" machine you've mentioned, the one behind the firewall, can access the Internet using Network Address Translation (NAT). This is kind of important, so please correct this assumption if it is false.)

When you create a tunnel, you specify an address and port on which it will answer, and an address and port to which it will be delivered. The -L option tells the tunnel to answer on the local side of the tunnel (the host running your client). The -R option tells the tunnel to answer on the remote side (the SSH server).

ssh tunnel directions

So... To be able to SSH from the Internet into a machine behind a firewall, you need the machine in question to open an SSH connection to the outside world and include a -R tunnel whose "entry" point is the "remote" side of his connection.

Of the two models shown above, you want the one on the right.

From the firewalled host:

ssh -f -N -T -R22222:localhost:22 yourpublichost.example.com

This tells your client to establish a tunnel with a -Remote entry point. Anything that attaches to port 22222 on the far end of the tunnel will actually reach "localhost port 22", where "localhost" is from the perspective of the exit point of the tunnel (i.e. your ssh client).

The other options are:

  • -f tells ssh to background itself after it authenticates, so you don't have to sit around running something on the remote server for the tunnel to remain alive.
  • -N says that you want an SSH connection, but you don't actually want to run any remote commands. If all you're creating is a tunnel, then including this option saves resources.
  • -T disables pseudo-tty allocation, which is appropriate because you're not trying to create an interactive shell.

There will be a password challenge unless you have set up DSA or RSA keys for a passwordless login.

Note that it is STRONGLY recommended that you use a throw-away account (not your own login) that you set up for just this tunnel/customer/server.

Now, from your shell on yourpublichost, establish a connection to the firewalled host through the tunnel:

ssh -p 22222 username@localhost

You'll get a host key challenge, as you've probably never hit this host before. Then you'll get a password challenge for the username account (unless you've set up keys for passwordless login).

If you're going to be accessing this host on a regular basis, you can also simplify access by adding a few lines to your ~/.ssh/config file:

host remotehostname
    User remoteusername
    Hostname localhost
    Port 22222

Adjust remotehostname and remoteusername to suit. The remoteusername field must match your username on the remote server, but remotehostname can be any hostname that suits you, it doesn't have to match anything resolvable.

share|improve this answer
+1 for tubes... – L0j1k Feb 20 at 7:45

ssh tunneling works by using the already established ssh connection for sending additional traffic.

When you connect to a remote server, you usually just have 1 channel for the normal user interaction (or 3 channels if you consider STDIN/STDOUT/STDERR separate). At any time, the local or remote ssh process can open additional channels on the existing connection. These channels then send/receive the tunnel traffic. When sending or receiving any traffic, the ssh process simply says "this traffic is for channel foobar".

It essentially works like this:

  1. You tell ssh to start listening on port XXXX and that any traffic received should be tunneled, and then set to Y.Y.Y.Y on port ZZZZ.
  2. The local ssh starts listening on port XXXX (generally on 127.0.0.1, but can be changed).
  3. Some application opens a connection to port XXXX on the local machine.
  4. The local ssh opens a channel to the remote ssh and says "any traffic on this channel goes to Y.Y.Y.Y:ZZZZ
  5. The remote ssh connects to Y.Y.Y.Y:ZZZZ and sends back the "OK, channel is open"
  6. Now any traffic sent along the connection to port XXXX on the local machine is proxied by ssh to Y.Y.Y.Y:ZZZZ.

This process is the exact same for both forward and reverse tunneling (just swap the words 'local' and 'remote' in the above procedure). Either side can start the tunnel. It doesn't even have to be when you first start ssh. You can open tunnels while ssh is already running (see ESCAPE CHARACTERS, specifically ~C).

For the role of -R, -f, -L, and -N, you really should just consult the man page, it gives you the best possible explanation. But I'll mention -R and -L.
-R tells the remote ssh to listen for connections, and that the local ssh should connect to the real destination. -L tells the local ssh to listen for connections, and that remote ssh should connect to the real destination.

Note, this is a very crude description, but it should give you enough info to know whats going on

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.