Thursday, March 4, 2010

Fun with port forwarding and SSH

No matter if your office computer has a public IP address, if you are part of a big organization, that computer will most likely be behind some big firewall, effectively isolating the internal network from external connections. In many occasions, however, the system administrators will not completely disable access, and will enable a gateway machine as the means for bridging connections from outside to the inside of the network. This gateway computer, nevertheless, tends to be quite limited, and most probable only allows secure connections via SSH (secure shell). Well, despair not, because giving you SSH access means that you could use that connection to piggyback other connections to other services inside any computer in the network, provided that the servers where those services are locates also have a SSH server. This is normally called tunnelling and port forwarding.

On the last couple of years I have lived with the inconvenience of having no access to my office computer. For some reason, I didn't care about this tunnelling business, or I thought they were rumours or that it would be too difficult to implement. How wrong I was. Obviously it has taken a couple of days, although probably I have only scratched the surface of what is possible. But now I am able to access not only my desktop computer remotely (with a display session and all), but also other services that I use inside my work's network that I normally need for my work (e.g database servers and subversion repositories). I will now briefly explain what it all boils down to.

Let's call the machines involved in this system client, gateway and target. We will use these names as addresses to those machines as well. Obviously, the first you need is an SSH client in client, and an SSH client/server in the other two machines. You also need an account in all those machines. First, lets make a key for the SSH connection between client and gateway so that you will not need to enter a password every time:

client:~$ ssh-keygen

Leave all the values to default and use no password (simply press enter). Now, copy the key to gateway:

client:~$ ssh-copy-id -i .ssh/ user_gateway@gateway_address

Now you can just ssh to gateway without using a password. Next, you might want to connect directly to target without having to SSH in gateway and from gateway to target. For this, you can set up a simple rule at your ssh_config file (normally in /etc/ssh/ssh_config) to forward text directly to targer through bridge:

Host symbolicName
HostName target
User user_target
ProxyCommand ssh user_gateway@gateway netcat -w 1 %h %p

Now you can "SSH symbolicName" and you will directly be prompted for the password of your target machine. But how to forward service ports? Well, with a command like this:

ssh -L port_client:target:port_target user_gateway@gateway

That command will take any connection requested in client to port port_client and will forward it to target to port port_target, using gateway as bridge. So the key to getting basically anything to your target machine is using localhost as the destination address when requesting the service, using port_client as the port (which obviously doesn't need to be the same port where the service is actually running on target). Confused? Right, is confusing at the beginning. For example, let's say that you have a SVN repository inside your work network, and when you are at your office computer, you use something like svn+ssh://machine_with_service/path_to_svn_repos as the URL to your service. In your computer outside of the work network, you will use the following svn+ssh://localhost/path_to_svn_repos, taking into consideration, of course, that the target machine we have been talking about before is machine_with_service in the example. Other service you can run like this is, for example, NX client and server, so you can get a graphical session of your office machine at home. Isn't that great?

All this can be done in Windows if that happens to be the OS that you using in your client. For that, you can use Putty. Putty has an option called "tunnelling", and you need to add your client's port and the target:target_port on this option tab for each service that you want to be forwarded. Then you only need to connect to the gateway machine in the usual way and there you go. Of course, the Putty window needs to remain open while you need port forwarding. More here and many other places on the net.

And this is all. Have fun with port forwarding too!

Note: Many thanks to Hugo for teaching me most of this!

No comments: