Wednesday, September 27, 2006

Accessing a machine behind a NAT using SSH remote port fowarding

Example situation (Real one)

My sister is not what you call a computer power user but she can use Windows XP and do some basic stuff (i.e. play flash games and listen MP3's). Now after years of phycological brain washing I finally convinced her to try a linux distro. Her choice is Ubuntu and she already installed it and has played a little with it.

Unfortunatelly not everything is perfect and now she has some problems basically because she messed up the sources.list of apt-get and has installed some non-standard packages downloaded directly from the Internet.

I have been trying to diagnose the problem but since I live at the other side of the world, literally, I can only see what she tells me and only give guesses on how to fix it via email and chat. As this was taking too much time the next step would be to login via ssh to her machine and find what is going on by myself, BUT, she is behind a firewall with NAT so she has a private IP address. She can access my PC via ssh but I cannot access hers. The solution?? the poweful ssh remote port forwarding.

Little Background

With SSH it is possible to forward any kind of traffic from one machine to another using port forwarding (tunneling). There are two kinds of port forwarding: remote port forwarding and local port forwarding. Both acomplish the same thing and differ only on the direction of the tunnel.

Local Port Forwarding

For the situation I presented above this method of port forwarding is not usefull. Actually I haven't found yet a good application for local port forwarding apart from creating a secure tunnel to transfer unencrypted data from my machine to another one. The idea is to create a tunnel between a port in my machine to a port in a remote machine. This way any connection to the port in my machine will be fowarded the the port in the remote machine.

As I said this is not usefull to solve my problem so I will not discuss this here. For some reference read the ssh man page and this link

Remote Port Forwarding

Let's review the situation: I need to connect to my sister's machine via ssh but she is behind a NAT so her machine is not accessible from the Internet. In the other hand she can access my machine from hers via ssh. The problem here is how can I get access to my sister's machine from mine?? simply ask my sister to create a tunnel between her machine and mine using ssh tunneling. This way I can simply connect to the tunnel port in my machine and ssh will forward it to her's.

How is this done?? with a simple command;

ssh -R 2222:localhost:22 my_ip_address

This is like a normal ssh connect command but with the -R switch that creates a tunnel. My sister has to run this command in her machine replacing my_ip_address with the IP address of my machine. After my sister excecutes the above command the tunnel created is like the one in the next image:

Everytime I want to connect to my sister's machine via ssh I simply connect to port 2222 on my own machine and magically I will be inside my sister's machine.

ssh -l sister_user -p 2222 localhost

Note that I am connecting via ssh to the port 2222 on my own machine, since this is a tunnel that my sister created it will be fowarded to the port 22 on my sister's machine where her SSHD server should be listening. This way I effectively get connected to her machine via ssh even if she is behind a NAT/Firewall or whatever.

Some additional notes

- First the sshd daemon must be running in port 22 on BOTH machines. This way my sister can connect via ssh to my machine and I can connect to hers via the tunnel.

- The port used in the remote machine (i.e. 2222) must be free for use, that is my machine must not be using that port. You can use any port but to use priviledges ports (< 1024) you must connect as root on the remote machine.

- By default this tunnel will be bound to the local address (i.e. so only connections to localhost are allowed. To bind to another address first we must make sure the GatewayPorts option is enabled on the ssh server (i.e. on my machine). Simply add this line to the /etc/sshd_config file: "GatewayPorts yes" and restart the sshd server with "/etc/init.d/ssh restart". This is in Ubuntu distro... other distros must be similar. Then my sister has to excecute the command by adding a bind address like:

ssh -R my_ip_address:2222:localhost:22 my_ip_address

This way anyone can connect to my sisters machine via ssh by connecting to port 2222 on mine:

From any PC on the world execute

# ssh -l sister_user -p 2222 my_ip_address

Note the difference here is that we are not limited to connect from within my machine only. Now anyone that knows my IP address and the tunnel port can connect to my sister's PC. What is this useful for? There are two situations I can think of in which this is useful:

- First if I am not expert enough to solve my sister's problem I can ask some Ubuntu guru guy to connect to my machine on port 2222 and he will be logged in my sister's machine. This way this guru guy can help me fix the problem even if he is also far away from me and my sis.

- Second situation would be that both, my sis and me, are behind a NAT. In this case nor can I access my sister's machine nor she can access mine via ssh. The solution is ask a third person with a ssh server accessible in the Internet to allow my sister to create a tunnel to his ssh server. Then I can connect to that server to access my sisters's. Something like the next image:

The obvious problem is that we need a willing person to allow us to use his/her ssh server as relay. Maybe using some hosting services with ssh login access can be used.

What about GUI applications??

With this solution I can diagnose and fix most of the problems via shell command but sometimes there are some configurations that are easier to fix by opening the graphical application per se. For example configuring Firefox or Konqueror to use proxy or configuring accounts and filters on Kmail/Evolution whatever... I know all these task can also be done in the shell command by editing the configuration files but the developers of all these applications took the time to create nice configuration GUI's and I want to honor them by using the configuration GUI's; apart that I really don't know all the configuration files as I use Kubuntu (KDE) while my sis installed Ubuntu (Gnome).

Fortunatelly SSH can help me here too!! by allowing X11forwarding if I connect to my sister's machine via ssh and excecute a GUI program (i.e. kate, kmail, konqueror) that application display will appear in my own PC!!, that is if I have X running and then I can play with those applications as if they were running on mine.

To do this we must ensure that the sshd server has X11Forward enabled. In Ubuntu/Kubuntu it is enabled by default so no modification is necessary. In case it is not enabled it is easy to enable it by adding this line "X11Forwarding yes
" to the /etc/sshd_config file and restarting the ssh server with "/etc/init.d/ssh restart". In my example this has to be done on my sister's machine.

After the server is enabled with X11Forwarding we must connect using the -X swicth like:

# ssh -X -l sister_user -p 2222 my_ip_address

And that's it!!. Now I can run any application on my sister's machine (GUI and non-GUI) and they all appear as being running on mine. This way I have full access to my sister machine and can do all kinds of diagnosis, tunning and fixing to give here the best Linux experience ever.

1 comment:

  1. Anonymous8:59 PM

    The clearest explanation I found in the net. Thanks my friend! It helped me a lot.