Secure Shell or SSH is a highly versatile application layer network protocol used for secure communication between networked hosts (in Server/client model). Designed as a replacement for telnet with Public-key cryptography for data confidentiality on unsecured networks ie. Internet.
SSH is most popular on Unix like systems and used for remote administration, tunneling, TCP and X11 forwarding and even file transfer (SFTP and SCP). This post will focus on SSH on windows as I mostly work with it, and for me one of the most interesting features – the SSH tunneling / TCP forwarding.
Most popular flavor on POSIX systems is OpenSSH, that includes ssh (the client), sshd (the SSH server daemon), scp, sftp and others.
On Windows: You can actually go with the same OpenSSH package under Cygwin (Unix-like environment for Microsoft Windows).
There are of course some Windows native servers and clients, notable:
KpyM Telnet/SSH Server, freeSSHd, the unbeatable PuTTY and its many forks with my favourite being KiTTY.
DD-WRT and Open-WRT feature Dropbear SSH server and client for its light use of resources.
Local port forwarding
Local port forwarding enables you to tunnel TCP traffic from your machine to ssh server or remote network that ssh server has access to.
SSH client on your local machine listens on specified port and forwards all TCP traffic to the specified destination address and port.
For example: VNC Viewer (with traffic destined to localhost on port 5900 > SSH client listening on port 5900 and forwarding traffic to the specified IP and port on server side of the tunnel -> server -> Other hosts that server has access to (optional).
Note that local port is arbitrary port number as long as you can specifiy it in software that you wish to tunnel.
PuTTy configuration for local port forwarding:
On Linux using OpenSSH client same thing can be achieved with:
ssh username@<ssh serve hostname or ip> -p <ssh port on the server> –L <local port being forwarded>:<destination ip>:<destination port>
Example: ssh firstname.lastname@example.org –p 22 –L 5900:10.0.0.1:5900
If you want other machines on local network to have access to a local port that is being forwarded to a remote network you should check “Local ports accept connections form other hosts” in PuTTY or add “-g” parameter if you are connecting from OpenSSH client.
Example: ssh email@example.com –p 22 –L 5900:10.0.0.1:5900 -g
Remote port forwarding
Remote port forwarding allows remote port (on the ssh server) to be forwarded to a localport and is very usefull for connecting to a host that is behind a firewall and proxy.
SSH tunnel would be established from PC behind the firewall with remote port forwarding to a localhost:port. You would connect to a work pc from SSH server or machine that has access to SSH server targeting the port that remote PC is listening on (on the other end of SSH tunnel )
OpenSSH client :
ssh username@<ssh serve hostname or ip> –R <remote port being forwarded>:<destination ip>:<destination port>
Example: ssh firstname.lastname@example.org -R 5900:127.0.0.1:5900
You can further expand the use of remote port forwarding by connecting from second cliend and forwarding its localport to a server and passing that traffic to a client that is listening on a remote port.
Lets say that you have a work PC that is behind a firewall establishes a tunnel to a SSH server that is accessible from the Internet (with remote port forwarding to a localhost).
Second PC establishes a tunnel to SSH server with local port forwarding with destination IP of the server and port that work PC is listening on (remote port set on work PC).
Picture is worth a thousand words, so it would look something like this:
To enable other machines (besides SSH server) on the remote network to have access to the tunnel/remote port that work PC is listening on, you’d have to check “Local ports accept connections form other hosts” and “Remote ports do the same” when establishing a tunnel from work PC to a SSH server.
Or if you are establishing a connection from OpenSSH client, you would make a remote port of the tunnel (server) listen on all the interfaces by adding *:
where * represents all interfaces (IP’s) that tunnel (server) should listen on, like this:
Example: ssh email@example.com -R *:5900:127.0.0.1:5900
Important notice: For this setup to work, you need to enable TCP port forwarding on SSH server, which is disabled by default in most cases.
When using OpenSSH server you would have to add “GatewayPorts yes” directive to a /etc/ssh/sshd_config
On DD-WRT this can be done thorough the web interface by going to services under Secure Shell just check Enable on SSH TCP Forwarding option.
Side note: VNC server usually requires that you allow loopback connections as putty traffic coming from remote port is passed through the local loopback interface.
Dynamic port forwarding (through local SOCKS proxy)
Dynamic port forwarding is useful when you want to tunnel traffic to any host that SSH server has access to. With dynamic port forwarding you don’t specify remote host or port, just local port that SSH client will use to listen as it acts as SOCKS proxy server.
Of course, traffic that will be tunneled this way must be from application that supports SOCKS proxy.
Most common practical use would be to tunnel web traffic through the SSH server.
OpenSSH client :
ssh username@<ssh serve hostname or ip> -D <local port for SOCKS proxy>
Example: ssh firstname.lastname@example.org -D 8080
Same rules/parametars apply for sharing local ports with other hosts as stated above.
Here is an example of browser configuration to tunnel web traffic through SSH server.
I encountered several issues with remote port forwarding :
- VNC session would hang if tunneled through the remote port while moving or clicking on PuTTY window, very weird problem that occurred in every configuration/vnc software that I tested.
Workaround – Use other SSH client or plink.exe (sort of a command line version of putty ).
- Remote port forwarding doesn’t work at all when PuTTY goes through HTTP proxy.
Workaround – Establish two tunnels to a server:
First tunnel that will forward local port for a second tunnel to the same SSH server.
Second tunnel that goes through the first, that will actually do the remote port forwarding.
Bonus: To keep my SSH tunnel established even if there was a connection drop I made a little AutoIT script for plink.exe
First make sure that you have saved PuTTY profile with everything set up, and some sort of web page on the remote side to check if tunnel is alive. I use DD-WRT about page.
#include <INet.au3> #include <Process.au3> HttpSetProxy(1) Global $URL = 'http://127.0.0.1:8080/About.htm' ; web page on the remote end of the tunnel, used to check for connectivity. $pid1 = '' While 1 If NOT (_INetGetSource($URL) = "") Then ; MsgBox(0, "", "Test site is online") Sleep(30000) Else ; MsgBox(0, "", "Test site is offline") sshtunel() Sleep(10000) EndIf WEnd Func sshtunel() If _ProcessGetName($pid1) = 'plink.exe' Then ProcessClose($pid1) Sleep(2000) $pid1 = Run('C:\PuTTY\plink.exe -load putty_saved_session', "", @SW_HIDE) ; putty_saved_session is the name of previously saved session in PuTTY EndFunc ;==>sshtunel