TCP forwarding in OpenSSH

If you've ever used the ssh program in your terminal, there's a very good chance the implementation you were using was OpenSSH. It would of course be kind of lame if all OpenSSH could do was remote shell access. In this post I'd like to show you one of its lesser-known features.

Forwarding

Using ssh with the -L flag you can use an SSH server as a TCP proxy and forward your traffic to a remote host. This will only work if AllowTcpForwarding is set to yes in the server's sshd_config. This might not always be the case since it's generally considered good security practice to disable this feature.

Now for a use case. Consider the following:

You're on a school network with an evil, fascist sysadmin who blocks ports 6667 and 6697 (the standard ports for IRC). Of course you should be paying attention to the class, but if there was an emergency that required you to be on IRC right away, you could do this:

$ ssh -L 1234:freenode.net:6667 example.com

         │    │                 └─ Server to route your traffic through.
         │    │
         │    └─ Destination you want to reach.
         │
         └─ Local port for SSH to listen to and forward from.

You can then let your IRC client connect to localhost:1234. The traffic will be tunneled (and thus encrypted) via the SSH connection. Keep in mind that the tunnel only protects the traffic between your machine and the remote SSH server. If you don't trust the owner/admin of the SSH server, you should take additional steps to protect your traffic, otherwise the owner of the server will be able to eavesdrop your connection very easily.

Reverse Forwarding

OpenSSH is also capable of reverse forwarding TCP packets. Let's assume you're running a web server on your local machine and that you'd like to make that server publicly available, but you don't control the network you're connected to and thus can't open up ports in the firewall. By running SSH like this:

$ ssh -R 8090:localhost:8080 example.com

... your web server running on localhost:8080 will now be reachable on example.com:8090. I used this feature on a shared server at Uberspace to get around my ISP's use of Dual-Stack Lite (which leaves you unable to use IPv4 port forwardings) and hosted my ownCloud and two Minecraft servers over SSH tunnels. As a temporary "duct tape" solution it works pretty well, especially when you don't have root on the remote server and can't set up a VPN.

Both of these features have a few more options that make them more useful. Run man ssh and have a peek at the options -N, -C and -t.