| SSH Port Forwarding |
| Written by Linux | |
| Tuesday, 08 August 2006 | |
IntroductionSSH is typically used for logging into remote servers so you have shell access to do maintenance, read your email, restart services, or whatever administration you require. SSH also offers some other native services, such as file copy (using scp and sftp) and remote command execution (using ssh with a command on the command line after the hostname).IntroductionSSH is typically used for logging into remote servers so you have shell access to do maintenance, read your email, restart services, or whatever administration you require. SSH also offers some other native services, such as file copy (using scp and sftp) and remote command execution (using ssh with a command on the command line after the hostname).Whenever we SSH from one machine to another, we establish a secure encrypted session. This first article in this SSH series[1] looked at properly verifying a server's host key, so that we can be sure that no attacker is able to perform a man-in-the-middle attack and gain access to read or manipulate what we do in that session. Other articles in this series looked at removing the need for static passwords using SSH user identities[2], and then using ssh-agent[3] to automate the task of typing passphrases. SSH also has a wonderful feature called SSH Port Forwarding, sometimes called SSH Tunneling, which allows you to establish a secure SSH session and then tunnel arbitrary TCP connections through it. Tunnels can be created at any time, with almost no effort and no programming, which makes them very appealing. In this article we look at SSH Port Forwarding in detail, as it is a very useful but often misunderstood technology. SSH Port Forwarding can be used for secure communications in a myriad of different ways. Let's start with an example.
LocalForward ExampleSay you have a mail client on your desktop, and currently use it to get your email from your mail server via POP, the Post Office Protocol, on port 110.[4] You may want to protect your POP connection for several reasons, such as keeping your password from going across the line in the clear[5], or just to make sure no one's sniffing the email you're downloading.Normally, your mail client will establish a TCP connection to the mail server on port 110, supply your username and password, and download your email. You can try this yourself using telnet or nc on the command line:
xahria@desktop$ nc mailserver 110
We can wrap this TCP connection inside an SSH session using SSH Port Forwarding. If you have SSH access to the machine that offers your service (POP, port 110 in this case) then SSH to it. If you don't, you can SSH to a server on the same network if the network is trusted. (See the security implications of port forwarding later in this article.) In this case, let's assume we don't have SSH access to the mail server, but we can log into a shell server on the same network, and create a tunnel for our cleartext POP connection:
# first, show that nothing's listening on our local machine on port 9999:
From a different window on your desktop machine, connect to your local machine (localhost) on port 9999:
xahria@desktop$ nc localhost 9999
Before we connected to the shellserver with SSH, nothing was listening on port 9999 on our desktop - once we'd logged in to the mail server with our tunnel, this port was bound by our SSH process, and the TCP connection to local port 9999 was magically tunneled through SSH to the other side. Let's describe how this works in detail, using the example above.
SSH Port Forward DebuggingLet's see it in action by using the verbose option to ssh:
xahria@desktop$ ssh -v -L 9999:mailserver:110 shellserver As you can see, there's a brief mention of port 9999 being bound and available for tunneling. We haven't made a connection to this port yet, so no tunnel is active yet. You can use the ~# escape sequence to see the connections in use. This sequence only works after a carriage return, so hit enter a few times before trying it:
xahria@shellserver$ (enter) You can see that there's only one connection, our actual SSH session from which we're typing those unix commands. Now, in a different window if we do a telnet localhost 9999, we'll open up a new connection through the tunnel, and we can see it from our SSH session using ~#
xahria@shellserver$ (enter) You can see that now we have both the SSH session we're using, plus a tunnel, the second entry. It tells you all you need to know about the connection -- it came from our local machine (127.0.0.1) source port 42789, which we could look up with netstat or lsof output if we were curious about it.
RemoteForward ExampleSSH Forwards actually come in two flavours. The one I've shown above is a local forward, where the ssh client machine is listening for new connections to be tunneled. A Remote Forward is just the opposite - a tunnel initiated on the server side that goes back through the client machine.The classic example of using a Remote Forward goes something like this. You're at work, and the VPN access is going to be down for maintenance for the weekend. However you really have some important work to do, but you'd rather work from the comfort of your desk at home, rather than being stuck at work all weekend. There's no way for you to SSH to your work desktop because it's behind the firewall. Before you leave for the evening, you SSH from your work desktop back to your home network. Your ~/.ssh/config file has the following snippet:
lainee@work$ tail ~/.ssh/config We've set up a tunnel using the RemoteForward option in the SSH configuration file. (We could have set it up on the command line using the -R option if we'd prefered.) Just to make sure our firewall doesn't kill the connection for inactivity, we run a ping for grins. Then we head on home. Later that evening, we can sit down on our home machine and see that we're logged in:
laineeboo@home$ last -1 Now comes the payoff - our tunnel is listening on our home machine on port 2222, and will be tunneled back through the corporate firewall to our work machine's port 22. So to SSH to work from home, since we have our tunnel ready, we simply point /usr/bin/ssh to port 2222:
laineboo@home$ ssh -p 2222 lainee@localhost Success! |