![]() |
![]() |
||||
A secure tunnel between two machines using the SSH protocol.
An SSH tunnel exists between an SSH client such as PuTTY/PLINK (Windows) or ssh on Linux, and an SSH Server (sshd). It can be used to securely connect a client on one machine to a server that is behind a firewall, by "tunnelling" all communications through the SSH connection.
The best way to describe an SSH tunnel is with a diagram.
Consider the following, which shows a normal connection between two machines:
CLIENT--------((internet))---------mysql.metawerx.net:3306
However, the server is behind a firewall for security purposes, so the client is unable to connect
CLIENT--------((internet))------|| FIREWALL ||-----mysql.metawerx.net:3306
Using SSH, we can create a way around the firewall, called a tunnel, which allows authentication and encryption of data.
CLIENT--------((internet))-----|| FIREWALL ||-----mysql.metawerx.net:3306 | | | ssh.metawerx.net --SSH==((internet))==========================SSHD--| this part is the secure SSH tunnel
Two more ports and hosts are now involved in the connection, making it more complex than before. However, the tunnel allows us to authenticate and send all traffic through the SSHD gateway server. To mysql.metawerx.net, the connection is now a local network connection. As a result, mysql.metawerx.net is now happy to accept our connection.
The following diagram shows all the port numbers being used above. This will be important when learning how the tunnel commands work.
CLIENT MYSQL localhost:anyport mysql.metawerx.net:3306 | | | | localhost:3307 ssh.metawerx.net:anyport |--SSH================((internet))==========================SSHD--| your_ip_address:anyport ssh.metawerx.net:22
As you can see, because of the connections, CLIENT thinks it is connected to a local database running on localhost:3307. Likewise, the MYSQL server thinks it is receiving a connection from ssh.metawerx.net (a local server, inside the firewall).
In this way, we are tricking the CLIENT and MYSQL by tunnelling all data securely between the two machines.
Now let's look at the command to establish the tunnel above. We will assume the following:
Windows:
c:\installers\putty\plink -C -v -l ssh_cassie -pw cassiepass -L localhost:3307:mysql.metawerx.net:3306 ssh.metawerx.net -------------- ----------------------- ---------------- CLIENT SIDE SERVER SIDE GATEWAY (SSHD)
Linux:
ssh -Cv -L localhost:3307:mysql.metawerx.net:3306 cassie@ssh.metawerx.net -------------- ----------------------- ---------------- CLIENT SIDE SERVER SIDE GATEWAY (SSHD)
The important parts are underlined.
If the tunnel is active and everything is working as expected, you should be able to connect to localhost:3307 with your client, and start interacting with the database. You can also try connecting with telnet.
telnet localhost 3307
If a blank screen appears, or something like the following, your tunnel is working well.
root@kirara:~# telnet localhost 3307 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. E 4.1.21-community-nt-log!m~Ui4cwMYV(`Connection closed by foreign host.
However, if you receive an error such as the following, your tunnel is not healthy.
telnet: Unable to connect to remote host: Connection refused
Let's look at some commands you can use to check that your SSH command is working the way you expected.
We can verify the CLIENT SIDE and GATEWAY parts of the command by checking if SSH is listening on the expected port. This is done by using netstat, which shows all listening ports and connections on your machine.
Windows:
C:\Documents and Settings\Administrator>netstat -na Active Connections Proto Local Address Foreign Address State TCP 127.0.0.1:1105 0.0.0.0:0 LISTENING TCP 127.0.0.1:3307 0.0.0.0:0 LISTENING <=== Yes, listening on 127.0.0.1:3307 TCP 127.0.0.1:8005 0.0.0.0:0 LISTENING (127.0.0.1 is the same as "localhost") TCP 192.168.0.18:53 0.0.0.0:0 LISTENING TCP 192.168.0.18:4400 0.0.0.0:0 LISTENING We are also listening on a lot of other ports, UDP 0.0.0.0:445 *:* but that is not important for this tutorial, UDP 0.0.0.0:500 *:* so just look for 127.0.0.1:3307, or whatever you UDP 127.0.0.1:53 *:* used in the CLIENT SIDE of the tunnel. UDP 192.168.0.18:53 *:* C:\Documents and Settings\Administrator>
On linux we use netstat as well. We will also use grep to ignore all lines except those that contain the text "3307" - the port we are checking for.
Linux:
root@kirara:~# netstat -pant | grep 3307 tcp 0 0 127.0.0.1:3307 0.0.0.0:* LISTEN 16930/ssh <=== Yes, listening on 127.0.0.1:3307 root@kirara:~# # If no lines are shown, you have nothing listening on port 3307
If you cannot see 127.0.0.1:3307 in the netstat command, your SSH program is not listening correctly, so retry the PLINK or ssh command.
If you close the tunnel by closing PuTTY/PLINK/SSH, you should notice that the listening port on 127.0.0.1:3307 disappears.
If you have verified that SSH is listening, then you have a good connection to the GATEWAY (SSHD) and the CLIENT SIDE of the tunnel appears to be working. If the tunnel itself still isn't active, then there could be a problem in the SERVER SIDE of the command. This can be seen in the logs on the server.
The point of this guide was to give a description of the way the tunnel works, and how to construct tunnels of your own.
If you are having problems setting up a tunnel, please continue by reading SSH Tunnel Troubleshooting, which contains guides to error messages and more help.