I've started writing something I hope will be an ebook called Take Control of SSH. It's an amazingly long process, so here's an excerpt -- the coolest trick, which initially made me want to write about SSH. This is for all those of you (us) who support family and friends remotely.

If you'd like to read the rest, please vote for Take Control of SSH.

Reverse Tunnel (Meet in the Middle)

This is a somewhat strange but very powerful feature. One of the problems with modern-day networking is that most computers are protected behind firewalls and/or Network Address Translation (NAT), meaning it may not be possible to connect directly to the computer you want to reach. For example, I sometimes want to remotely control my father's PowerBook to help with a problem, but he has a private dynamic address, behind an AirPort Extreme base station which itself has another dynamic address and provides NAT. Even if my father told me his IP address and his base station's address, I wouldn't be able to reach his PowerBook. Reverse tunneling works around this by allowing him to "project" a tunnel to another computer. If I can reach that computer, the tunnel connects back to his computer. Because he establishes the reverse tunnel from his computer as a client, he doesn't have trouble with (Network Address Translation) NAT, and he doesn't even have to know his own IP address. For reverse tunneling to work, my father and I both need access to a computer running sshd. In this example, my PowerBook is called pb, his is called dad, and the server is www.reppep.com.

Note that reverse tunneling provides access to the tunneling computer, and so could be a violation of network security policies. The tunnel is restricted (only accessible from the gateway computer, or other systems with access to it), but it is important to check with the network administrators before implementing a reverse tunnel. In addition, reverse tunneling is fairly complicated. A simpler option is to make SSH directly accessible, but unfortunately this often cannot be arranged. If you'd like to read more about configuring dynamic DNS and firewalls for direct SSH access, please vote for Take Control of SSH.

To use Remote Desktop through a reverse tunnel and an intermediate system, there are several steps (this can be simplified if the client is directly on the Internet and accessible via ssh). There might be as many as 3 separate encryption/decryption cycles in this scenario, but performance is generally decent.

These instructions were originally written for Apple Remote Desktop 2, but apply equally to Remote Desktop 3. Generally, I strongly suggest connecting with Remote Desktop 3's "Encrypt all network data (more secure)" option, but in this case it doesn't do quite what is needed, and would only add a redundant extra layer of encryption.

  1. On the computer to be controlled (dad in this example), make sure Apple Remote Desktop is enabled in System Preferences:Sharing:Services.
  2. On the computer to be controlled (dad), open a couple ports on the server and point them at the ssh and VNC servers on dad, by typing the following into a Terminal window. The sleep command ensures the tunnels will be accessible for at least an hour -- they stay open automatically while in use:
    ssh -R 6900:127.0.0.1:5900 -R 6922:127.0.0.1:22 www.reppep.com sleep 3600
  3. On the machine running Remote Desktop.app (pb in this example), set up tunnels to those ports on the server:
    ssh -C -L 6900:127.0.0.1:6900 -L 6922:127.0.0.1:6922 -o HostKeyAlias=dad www.reppep.com
  4. Now you can log into dad with:
    ssh -p 6922 www.reppep.com
  5. Alternatively, you can connect to 127.0.0.1:6900 with Remote Desktop (or port 6900/display 1000 in a VNC client), and control dad.

Note that if the firewall in Mac OS X (non-Server) is on, and any services are enabled in System Preferences:Sharing:Services, the appropriate network ports are automatically opened in the firewall, accessible to the entire Internet; this is overly exposed. OpenSSH can be restricted with TCP Wrapper; the Apple Remote Desktop agent (which is a VNC server at its core) cannot; VineServer has an option to only listen on the loopback address, so external hosts cannot connect -- or even detect the presence of a VNC server -- without first establishing an ssh tunnel.

http://www.redstonesoftware.com/products/vine/server/

To make this easier for my father, I made sure he uses the same login name on www.reppep.com as on dad, and I gave him a double-clickable file (ssh-tunnel.command) to run step #2 (the part he has to do each time I'm going to help him), in his Dock, to establish the ssh tunnel. Files ending with .command are automatically executed by Terminal when opened in Mac OS X.

To see what TCP ports are accepting connections, use "netstat -an | grep LIST". Step #2 creates tunnels on the server's ports 6900 & 6922 (connected back to dad), and step #3 opens the same port numbers on the client (pb), tunneled to the server.

When tunneling ssh connections through ssh, the ssh program tends to show a "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!" alert, because ssh gets confused about which ssh server it's connecting to. The short-term fix is to edit ~/.ssh/known_hosts and remove the entry for 127.0.0.1 or localhost. If you would like to learn more about the cause and other options for dealing with it (including HostKeyAlias, shown in the example above), please vote for Take Control of SSH.