ssh tunnels

Thursday, January 17, 2008

Using ssh we can create tunnels to route bi-directional traffic. Depending on our selection of destination and server computers to connect to, the complete tunnel is made of a fully secure ssh tunnel, and possibly an additional tunnel continuing on that is not secure. The examples below should help explain this.
Here's the command:

ssh -NL localport:targethost:hostport server [-p serverport]

Where

  • -N means don't start a remote ssh session (useful if just port fowarding)
  • -L indicates a tunnel is to be set up with the following params:
    • localport: tunnel 'entry'. Port number to connect to locally (ie at localhost)
    • targethost: tunnel 'destination'. Which computer (name or ip) to connect to
    • hostport: tunnel 'exit'. Port number to appear as on the other side of the tunnel.
  • server: computer to validate ssh connection on (needs to be running ssh server). This forms part of the tunnel and three variations of this are explained below. You can make this 'user@server' in order to specify a username for the authentication if required.
  • serverport: this is optional, but if you want to create the ssh connection over a non-standard port (ie not 22) then use this. You'll need to get the sshd listening on the new port in this case.
Remember these funky things are 2-way so if whatever you're communicating with at the other end of the tunnel sends info back down the tunnel (via hostport) then you'll get it right back at your end (localport). It's cool.

Example 1, target computer is running ssh server:
ssh -NL 8081:192.168.1.4:8090 192.168.1.4
Create a tunnel from 8081 locally to 192.168.1.4, and appear there at port 8090. Validate at 192.168.1.4. This is a short tunnel, between just the client and host, but completely secure. All traffic in this case will be over port 22 (ssh default).

Example 2, host computer is running ssh server:
ssh -NL 8081:192.168.1.4:8090 localhost
Exactly as in example 1, only this time the local machine is both ssh server and client. There is effectively no secure tunnel here (ie it's only between ports on the local machine), so unsecure over port 8090 to 192.168.1.4.

Example 3, 3rd computer is running ssh server:
ssh -NL 8081:192.168.1.4:8090 192.168.1.5 -p 3389
In this case, locally we are the ssh client, connecting securely (over port 3389) to the ssh server, 192.168.1.5. From there traffic travels over port 8090 to the destination box, 192.168.1.4. This is very powerful as traffic can be securely routed into a limited-access network. For example in this case if Microsoft's Remote Desktop Protocol (RDP) was the only traffic allowed in and out (eg through VPN), then the client externally can run this command, connect through on the RDP port (3389), connecting to a box inside the network (192.168.1.5). From there the destination IP is resolved, so this needn't be visible from the client computer, and traffic flows freely inside the network over 8090.

Another option is remote tunnels (instead of local tunnels). These use essentially the same commands, but with -R in place of -L. With a remote tunnel it is possible to declare a port on a foreign machine as the tunnel entry.

A nice way to test your tunnel is to use netcat. For the above examples this test would be:

On 192.168.1.4:
nc -l -p 8090
listen (-l) on port (-p) 8090 - end of the tunnel

On localhost:
nc localhost 8081
connect to localhost on 8081 - start of the tunnel

The localhost connection should get tunneled to the remote box and you'll be able to type at either end and see it appear in the terminals.