So this is pretty basic stuff, but I find myself looking up the exact procedure a few times a year because I forget some minor detail somewhere. The basic premise is that I want to connect to a host, but that host can only be connected to by another host. So the whole chain looks like this:
The client can connect to Host 1 as long as he has the private key matching the public key on Host 1 (along with the password for the private key). Host 1 can connect to host 2, again using a key. Host 2 can connect to the local address (Host 2 has a wan and a lan address) of the Target Server with a username and password (a Windows Box in this case). Of course, you can do all this with just password authentication, but I wanted to have the added security of “something I have” (the key) and “something I know” (passwords). The main goal is to allow the Client to connect to the Target Server via RDP (TCP 3389), using SSH tunnels all the way. I will affix Wireshark and tcpdump captures from the different points to show the traffic.
Client to Host 1
First we will establish an SSH Tunnel between Client and Host 1. To do this from our Windows Client machine, we open up putty, and perform the following configurations:
Under “Source port” I added 8080. You can obviously use any convenient port that doesn’t overlap with something that’s listening on your local (the Client machine) machine. Under “Destination”, type in localhost:8080. This is so that the end of the tunnel on Host 1 will be localhost:8080. Save your configuration for easy access later. We will further connect through this to Host 2, and on to the Target Server.
Host 1 to Host 2 and on to Target Server
From the putty connection to Host 1, I can now create a tunnel between Host 1 (port 8080) and Host 2, and make the other end of the tunnel Target Server port 3389 (for RDP). The command used for this is:
ssh -L 127.0.0.1:8080:targetserver.ip.address:3389 host2username@host2ip
The man-page for ssh, under -L says:
-L [bind address:]port:host:hostport.
Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the remote machine.
In this case it’s our end of the first tunnel, port 8080 on “localhost” (i.e. Host 1)
Client to Target Server
Now when all is done, we can start a Remote Desktop connection from Client all the way to Target Server. The connection parameters in my example is like so:
First we have a Wireshark capture from Client to the tunnel which terminates at Target Server. Of course, Client doesn’t know this, so from it’s point of view, it’s making an ssh connection to Host 1.
All nice and neat and SSH.
Next up, we have the view from Host 1, capturing for traffic coming from Client, and going to Host 2:
Nothing human readable. Arguments for tcpdump were: tcpdump -i eth0 -n -X -vv host ip.address.of.host2
The penultimate capture! Host 2’s prespective:
Internal addresses all the way here, from Host 2’s internal address to Target Server’s internal address
Finally, Wireshark capture from Target Server, traffic is seen as coming from Host 2:
So here we have it. A two-hop SSH tunnel that allows you to use RDP from a client somewhere, to a machine inside a private network that can’t be otherwise reached.
Disclaimer: I’m not responsible for any misconfigurations or anything, really, that causes you to end up on the front page of newspapers everywhere, lose data, face, or other features you hold dear. Also, I recognize there are about a gazillion ways to do this; This one is mine.
P.S. I also know RDP already has a lot of built in security and encryption, but I’m still not comfortable opening up a direct path to my home machine, or any other machine for that matter from all of the interwebs. Also, this was fun to do and a nice thing to learn about.