SSH Tunneling - also known as "Port Forwarding on Steroids"

February 2, 2013
If you need to access network resources behind a firewall, you could set up lots of port forwards. But it can be cumbersome to manage a large volume of these, and depending on the protocol, this practice may be insecure. Instead, why not use an SSH tunnel? An SSH tunnel is an excellent method for handling encryption and authentication. An equally effective alternative to an SSH tunnel is a VPN. The one to choose will largely depend on your situation and personal preference. For our purposes, we prefer SSH. The following example describes how to set up an SSH tunnel between two Linux servers. In our case we've used two Western Digital My Book Live devices. However, you may use any device such as a traditional server, VPS, or router. If you use Windows, you may use the excellent SSH client PuTTY to create a tunnel between you and the SSH server. First, let us create the SSH tunnel. Assume for this example an employee wishes to connect via SSH to a small office network. You should set up one single port forward on the office's router - a random port number to the machine operating the SSH server. Employee's My Book Live: 192.168.1.2 Employee's computer: 192.168.1.3 Office My Book Live: 192.168.0.2 Office printer: 192.168.0.100
ssh -p 19368 \
-L :9100:192.168.0.100:9100 `: Printer` \
-R :5500:192.168.1.3:5500   `: Reverse port forward VNC Listening Viewer` \
-D :8080                    `: SOCKS5 proxy server.` \
user@office-ssh-server.example.com
Let's explain things line by line. ssh -p 19368 instructs ssh to connect to office-ssh-server.example.com on port 19368. This is a random number - we recommend not using the default port of 22 unless absolutely necessary. -L :9100:192.168.0.100:9100 sets up a local port forward via the SSH tunnel. Perhaps the employee wants to access the office printer from home. The printer driver for the printer at 192.168.0.100 doesn't support proxy servers, so this forward must be defined explicitly. The employee may now configure his printer port to use the IP address 192.168.1.2 on port 9100 - traffic sent here will be forwarded to 192.168.0.100 on port 9100. -R :5500:192.168.1.3:5500 sets up a remote port forward. Perhaps the employee wants to run VNC Listening Viewer on his own computer and accept connections from the office. In this case, traffic from the office's LAN sent to 192.168.0.2 on port 5500 will be forwarded to the employee's computer 192.168.1.3 on port 5500. This is an excellent technique for securing VNC Single Click. For this to work, you should add GatewayPorts clientspecified to the /etc/ssh/sshd_config file on the office SSH server, then restart the SSH server. -D :8080 sets up a dynamic port forward and causes ssh to act as a SOCKS5 server. Instead of setting up dozens of forwarded ports for access to various resources, this proxy will do the trick. Once you've set up everything as you want it, you may wish to use the options -f -N so that ssh will run in the background. For additional security, you may wish to set up an RSA key for authentication. If the SSH tunnel needs to stay up through long periods of inactivity, you may want to set ServerAliveInterval. Open your ~/.ssh/config file (or create it with 600 permissions if it doesn't exist) and add the following to it. (You may need to adjust the number based on your router's timeout settings.)
ServerAliveInterval 60
You may notice that from time to time the SSH tunnel is dropped, yet you can't re-establish the remote port forward. (A common cause of this is not setting ServerAliveInterval as described above.) This code will terminate whatever process on office-ssh-server.example.com is listening on port 5500:
ssh -p 19368 user@office-ssh-server.example.com 'kill $(lsof -i tcp:5500 -t)'
The local port forward and the remote port forward are quite straightforward to use. There are a few ways to use the dynamic port forward. This is one way to configure Firefox to route all traffic via the SSH tunnel: But what if you don't want all traffic via the tunnel? Perhaps instead you'd like normal internet traffic to be routed directly. This can be accomplished with an automatic proxy configuration file: The contents of the file:
function FindProxyForURL(url, host) {
 if (isInNet(host, "192.168.0.1", "255.255.255.0")) {
  // alert ("Must send " + host + " via proxy.");
  return "SOCKS 192.168.1.2:8080";
  } else  {
  // alert (host + " is ok to send direct.");
  return "DIRECT";
  }
 }
The alerts may be useful for testing purposes, (they may be viewed via the Firefox error console) but should be commented out for production use to avoid filling up your logs. Now, the employee may use one single browser to access both the internet and seamlessly also access internal IPs 192.168.0.x behind the office's firewall, via the SSH tunnel.
Name: Email: (Required only if you want a reply.) Comment: