Posted 2006-11-11T17:27:00+01:00 in unix recipe web
You may be familiar with SSH as the secure terminal alternative to venerable telnet. However, SSH can do much more than just running a terminal to a remote computer. One of the interesting features is its port forwarding capability. This feature is documented in RFC 4254, Chapter 7, TCP/IP Port Forwarding.
For a setup at work I want to connect to a database server in a remote network. I can only access this network with SSH through the remote firewall. The firewall is blocking all traffic except SSH and HTTP, i.e. TCP connections on port 22 and 80 . Luckily, SSH is all I need to get to the database server. The SSH port forwarding feature allows me to create a (TCP/IP) tunnel over the network, through the firewall.
An SSH tunnel is not the same as a kernel level tunnel, such as BSD's tun. But that's OK to me in this case, since I'm connecting from a Debian GNU/Linux computer to an IBM pSeries AIX server. I don't want to delve into any AIX specifics, so SSH lowers the required level of knowledge as well :-).
As a bonus, the tunnel is encrypted, so the traffic that goes over the tunnel cannot be sniffed while in transit on the Internet.
I ended up with this command:
jeroenp@tripel:~$ ssh -f -N -L localhost:4321:dbms.tycoon.com:3306 jeroenp@remote.tycoon.com
Explanation of command flags
The tunnel command in SSH is -L
followed by a specification of which
start point to connect to which end point:
-L [bind_address]port:remote_host:hostport
I ended up with this -L specification:
-L localhost:4321:dbms.tycoon.com:3306
Two flags where added to the ssh command to make this tunnel work practically. If you leave them out, you'll start an ordinary SSH shell session, along with the tunnel;
-N
indicates that no remote command, such as a shell,
will be started. That's just what I need, since I'm only interested
in the tunnel.
-f
forks the ssh command from the shell, so that the SSH
tunnel runs in the background and you can safely disconnect
the terminal.
You can now connect to the database as if it were a local process. For example with the MySQL command line client:
jeroenp@tripel:~$ mysql -h localhost --port=4321
--protocol=TCP -u admin -p
The hostname for the database is now localhost. The value for port is the left, local port from the -L flag in the ssh command.
This recipe assumes you have a working SSH connection to the remote SSH server. Try running a SSH shell first, before you start experimenting with the tunnel. It is also worthwhile trying to run a command to connect from that SSH server to the final endpoint. E.g. in my case running:
jeroenp@remote.tycoon.com:~$
mysql -h dbms.tycoon.com -u admin -p
Another gotcha that got me: In case you're running a MySQL database on localhost as well, you may need to specify the protocol, to prevent MySQL from connecting to your local database server via your local UNIX domain socket.
The port forwarding principle is really simple, and is often used as a secure wrapper around POP3 email retrieval over a WLAN (WiFi) network. Instead of a MySQL database server, you might as well connect to Oracle, PostgreSQL or a JDBC database on port 1521.
If you want to go one step further, you could even connect the entire local and remote networks over the SSH tunnel. This HOWTO uses PPP to convert packets into a character stream and SSH to encrypt it and transmit it to the remote computer.
I added some extra flags to the final SSH command
-n
reconnects stdin to /dev/null so that no
accidental character input is
send over the line (but not the tunnel).
-6 tells SSH to only listen to IPv6.
This saves an open socket. Which is fine and neat.
-2
just to be sure, only connect with the SSH v2 protocol.