SSH From the Inside

### Problem ###

I need SSH access to a particulr machine (*schoolsvr*) which is behind a NAT. I only need to enable access from a single client (*homesvr*), which has a public IP address of its own. Both machines are running **sshd**. I can access *homesvr* from a shell on *schoolsvr*, but not vise-versa.

If I had admin access on *schoolsvr’s* gateway, I could alter the NAT to forward some unused port (say, 12345) to *schoolsvr:22*, which would allow me to SSH to *schoolsvr* using the gateway’s public IP and port 12345. Unfortunately, I don’t have admin access to the gateway.

How do I enable SSH access to *schoolsvr*?

### Solution ###

The solution is to open an SSH tunnel from *schoolsvr*, which I can access from a shell on *homesvr*. To achieve this, I use the OpenSSH client program’s `-R` option to bind an SSH tunnel to a non-standard port on *homesvr*. Consider the following command:

nick@schoolsvr$ ssh -R 12345:localhost:22 nick@homesvr
nick@homesvr’s password:

This command connects to *homesvr* via the standard SSH port (22) and binds that connection to the specified bind port (12345). This port remains bound until the SSH session is terminated. Now all SSH traffic directed to port 12345 on *homesvr* will be forwarded to port 22. When I get back to *homesvr*, I can open a new SSH session with *schoolsvr* using the following command:

nick@homesvr$ ssh -p 12345 localhost
nick@localhost’s password:

I’m in! I can terminate this session when I am finished, and the original tunnel remains open until I kill it on *schoolsvr*.

This command can be set up in */etc/inittab* (or an Upstart config file, depending on your system configuration) with the `respawn` action, which would ensure that the tunnel is open upon boot and will be automatically reopened upon termination. Note that such a setup requires the appropriate SSH keys to be configured on both machines, as an init process can’t enter a password.

Because each half of the connection is done using SSH, this setup is completely secure. Of course, anyone with physical access to *schoolsvr* would have full control over the open login to *homesvr*. To prevent this, I can modify the original command as follows:

nick@schoolsvr$ ssh -nNT -R 12345:localhost:22 nick@homesvr &

The `-n` option redirects standard input from */dev/null*. The `-N` option is specifically designed for port-forwarding applications such as this, and tells SSH not to bother preparing a command stream for this connection. The `-T` option tells the remote host not to bother allocating a pseudo-tty for this connection. These three options eliminate the possibility of using this open tunnel to execute any other processes on *schoolsvr*. Additionally, I appended an ampersand (`&`) to send the process to the background. Now I can close the shell in which I ran the command without killing the process.

### Conclusion ###

While not as elegant as a true NAT-based port forwarding solution, reverse SSH tunnels are a fast, secure way to connect two remote machines for general use. When used with discretion, they can be a real time-saver.

What do you think of this solution? Did I leave anything out? Let me know in the comments.

Leave a Reply

Your email address will not be published. Required fields are marked *