Hack #96. Forward and Encrypt Traffic with SSH

Keep network traffic to arbitrary ports secure with SSH port forwarding.

In addition to providing remote shell access and command execution, OpenSSH can forward arbitrary TCP ports to the other end of your connection. This can be extremely handy for protecting email, web, or any other traffic that you need to keep private (at least, all the way to the other end of the tunnel).

ssh accomplishes local forwarding by binding to a local port, performing encryption, sending the encrypted data to the remote end of the ssh connection, and then decrypting it and sending it to the remote host and port you specify. Start an ssh tunnel with the -L (short for “local”) switch:

# ssh -f -N -L 110:mailhost:110 
            
               user
            
            @
            
               mailhost
            
         

Naturally, substitute user with your username and mailhost with your mail server’s name or IP address. Note that you will have to be root for this example, since you’ll be binding to a privileged port (110, the POP3 port). You should also disable any locally running POP3 daemon (look in /etc/inetd.conf); otherwise, it will get in the way.

Now, to encrypt all of your POP3 traffic, configure your mail client to connect to localhost port 110. It will happily talk to mailhost as if it were connected directly, except that the entire conversation will be encrypted. Alternatively, you could tell ssh to listen on a port above 1024 and eliminate the need to run it as root; however, you would have to configure your email client to also use this port, rather than port 110.

-f forks ssh into the background, and -N tells it not to actually run a command on the remote end, but just to do the forwarding. One interesting feature when using the -N switch is that you can still forward a port, even if you do not have a valid login shell on the remote server. However, for this to work you’ll need to set up public-key authentication with the account beforehand.

If your ssh server supports it, you can also try the -C switch to turn on compression. This can significantly reduce the time it takes to download email. To speed up connections even more, try using the blowfish cipher, which is generally faster than 3des (the default). To use the blowfish cipher, type -c blowfish.

You can specify as many -L lines as you like when establishing the connection. To also forward outbound email traffic, try this:

# ssh -f -N -L 110:mailhost:110 -L 25:mailhost:25 
            
               user
            
            @
            
               mailhost
            
         

Now, set your outbound email host to localhost, and your email traffic will be encrypted as far as mailhost. Generally, this is useful only if the email is bound for an internal host or if you can’t trust your local network connection (as is the case with most wireless networks). Obviously, once your email leaves mailhost, it will be transmitted in the clear, unless you’ve encrypted the message with a tool such as PGP or GPG [Hack #42].

If you’re already logged into a remote host and need to forward a port quickly, try this:

  1. Press Enter.

  2. Type ~C (it doesn’t echo).

  3. You should be at an ssh> prompt; enter the -L line as you would from the command line.

For example:

rob@catlin:~$ 
rob@catlin:~$ ~C
ssh> -L8000:localhost:80
Forwarding port.

Your current shell will then forward local port 8000 to catlin’s port 80, as if you had entered it in the first place.

You can also allow other (remote) clients to connect to your forwarded port, with the -g switch. If you’re logged into a remote gateway that serves as a network address translator for a private network, use a command like this:

$ ssh -f -g -N -L8000:localhost:80 10.42.4.6
         

This forwards all connections from the gateway’s port 8000 to internal host 10.42.4.6’s port 80. If the gateway has a live Internet address, this allows anyone from the Net to connect to the web server on 10.42.4.6 as if it were running on port 8000 of the gateway.

One last point worth mentioning is that the forwarded host doesn’t have to be localhost; it can be any host that the machine you’re connecting to can access directly. For example, to forward local port 5150 to a web server somewhere on an internal network, try this:

$ ssh -f -N -L5150:intranet.insider.nocat:80 gateway.nocat.net
         

Assuming that you’re running a private domain called .nocat, and that gateway.nocat.net also has a connection to the private network, all traffic to port 5150 of the remote host will be obligingly forwarded to intranet.insider.nocat:80. The address intranet.insider.nocat doesn’t have to resolve in DNS to the remote host; it isn’t looked up until the connection is made to gateway.nocat.net, and then it’s gateway that does the lookup. To securely browse that site from the remote host, try connecting to http://localhost:5150/.

Rob Flickenger