I often here people saying something like

SSH to your home PC? Sitting behind a NAT? A snowball's chance in hell...

But is it really impossible?

What is a NAT?

NAT (network address translation) is a technique to cover multiple clients behind one router. Kristian Köhntopp explained the technology very well in his article NAT ist kein Sicherheitsfeature (GER). But let me summarize some things. Here is a small image to visualize the topology of an example network:

You see, the NAT represents something like a bridge between it’s clients (in network ) and the rest of the world. The connections of the clients are translated by this router. Assuming client wants to speak to my webserver , he sends a packet containing, among others, the following information:


So all machines on the way from to know whom to send the packet next. When this packet arrives at the NAT, the NAT will rewrite it. The NAT stores a table for all recent connections. Each entry consists of a client IP, client port and a local port on its public interface. For our example the table entry for this example might look like:

Source IPSource PortNAT IPNAT Port

The resulting port on the NAT is arbitary, it’s just one free port.. Each packet arriving on port 1234 of the public interface of the NAT is forwarded to . Our rewritten packet> now contains the following informations:


and is send to the next node in the world wide web. Nobody out of will ever know that there is a machine requesting a website from . The webserver on will send it’s answer to the pretended source, , and the NAT will forward the traffic according to its table entry to .

Why do NAT’s exists? The solely plausible reason seem to be the lack of IPv4 addresses. With a NAT an ISP just need to offer a single IP address for a huge bunch of clients. Hopefully this will change in times of IPv6!

Why does it seem to be impossible?

Since the private network is not known by the outer world (it is simply not route-able in the Internet, see wikipedia), you cannot connect from outside straight to . The WWW will only see as source for all the clients. That means all clients in have the same public IP for each machine that is not in . So how to access ? Speaking to will result in crap, you don’t know which port will be forwarded to whom!? If it is forwarded at all…

How is it nevertheless possible?

Method one...

…is not very nice, if you are looking for a real solution please skip this paragraph and continue with solutions two and three ;-) Since there is no entry in the NAT table that specifies an outside target, you can send packets from any location to and the NAT will forward them to (according to my example). So to create a path from outside to ‘s SSH server you just need to send a packet from to any server outside that informs you about the source IP and source port that was reported by the NAT (it’s the address that will be forwarded to the client). If you immediately connect to this address, and if a SSH server is listening on , you should be able to establish a SSH session. Simple isn’t it ;-) To get this working you could try something like repeating the following commands frequently:

# stop SSH to free the port
/etc/init.d/ssh stop

# send a packet to somewhere that is configured to notify you about the NAT settings
# the foreign side should instantaneously close the connection
# so the netcat command doesn't block your script
netcat -p 22 binfalse.de 1337

# restart SSH to get ready for connections
/etc/init.d/ssh stop

Of course you can also install some iptables rules to rewrite the TCP packets. So you can send the packets from some other ports than 22 , iptables will rewrite them so the target machine (and the NAT) thinks they came from :22 . With this setup you don’t have to stop SSH, because you don’t need the free port… But just hack it your way ;-)

Method two...

…is much more comfortable. You can set up a reverse SSH tunnel! Again you need another machine outside the NAT, that has a SSH server running and will act as your gateway. Just connect to it from your local machine behind the NAT:

ssh -R 1337:localhost:22 you@your.server

That will open the port 1337 on your.server . All packets arriving at this port are transferred through the SSH tunnel to your home PC. Run something like screen or top on the server to always transfer packets (otherwise the connection will be closed after some time), with -o ServerAliveInterval=XXX you can adjust the threshold for closing the SSH connection. Surround it with a while loop and you’ll reestablish closed connections (network errors or something like that):

while [ 1 ]; do ssh -o ServerAliveInterval=60 -R 1337:localhost:22 you@your.server; done

By default the opened port is just bound to (the servers loopback interface), so you can only send packets from the server itself (or need some more network hacking). To have this hack listening to (all interfaces) add the following to your /etc/ssh/sshd_config on your.server :

GatewayPorts yes

and restart the daemon.

Method three...

…might be the most elegant. Set up a VPN! But that’s too much for now, request some explanations from 3dfxatwork, he’s your OpenVPN guy!, and take a look at Dirty NAT tricks to get a VPN to work with clients also numbered in the private address space

So you see, no hasty prejudices ;-)

Martin Scharm

stuff. just for the records.

Post a comment

read more about submitting comments