Forwarding Ports over SSH

Port forwarding, or ssh tunneling, is a way to forward insecure TCP traffic through SSH Secure Shell. You can secure for example POP3, SMTP and HTTP connections that would otherwise be insecure, or bypass firewall rules, preventing you to access a remote service.

There are two types of port forwarding: local and remote.

Local port forwarding forwards traffic coming to a local port to a specified remote port. For example, all traffic coming to port 1234 on the client could be forwarded to port 23 on the server.

Remote port forwarding does the opposite: it forwards traffic coming to a remote port to a specified local port.

Local port forwarding

Let's assume we want to connect to a VNC server on a remote host from our laptop, but to secure the connection we want to tunnel the traffic through SSH. To accomplish this, let's run the following on our local machine :

[root@laptop]# ssh user@remotevnc.org -L 10000:remotevnc.org:5901 -N -f -C
This will create a SSH connection to remotevnc.org, backgraound it (-f), compress it (-C) and will not allow the execution of any remote SSH commands (-N) and will listen on localhost on port 10000. All we need to do now, is configure our VNC client to connect to localhost on port 10000 and SSH will forward the VNC traffic to remotevnc.org. You can see this by running netstat on your local machine where you created the tunnel:

[root@laptop]# netstat -antup | grep 10000
tcp   0   0   127.0.0.1:10000   0.0.0.0:*   LISTEN   818/ssh  

If we would like to offer this connectivity to other clients on our network, we can specify -g, which will bind port 10000 on all interfaces, allowing other clients on the local network to connect to our laptop on port 10000 using VNC and end up redirected to remotevnc.org.

Another use of local SSH port forwarding is if we are behind a restrictive firewall which does not allow outgoing SMTP connections except to a designated mail server. We want to connect to a different mail server however, mail.example.net, on port 25. We also have an SSH account on a machine oursshserver.org, which does not reside within the restrictive firewall and can thus access port 25 on mail.example.net.

With standard SSH port forwarding, we can use the following:

[root@laptop]# ssh user@oursshserver.org -L 2525:mail.example.net:25 -N -f -C

This will forward port 2525 on our laptop to port 25 on mail.example.net, by way of (or through) oursshserver.org and it will be encrypted from our laptop to our server. All we need to do after that is to configure our mail client to send mail to localhost, port 2525.

We can also forward ports locally. For example the bellow will forward port 80 to port 8080.
[root@laptop]# ssh user@localhost -L 8080:localhost:80 -N -f -C 

Remote port forwarding

Let's assume that we have an Apache server running in our local network behind a NAT device, at home, with an IP address of 192.168.1.100, that we would like to access from the internet. As long as we have an ssh access to a publicly reachable server from our home server, we can create a remote tunnel to that server, such that it will receive traffic and forward it back encrypted to our internal Apache box:

[root@laptop]# ssh user@publicserver.org -R 8080:192.168.1.100:80 -N -f -C

To allow for port 8080 to bind on all interfaces on publicserver.org for everyone to connect to, add this to sshd_config and restart sshd, since the above-mentioned -g option does not work with remote port forwarding:

[root@publicserver]# vi /etc/ssh/sshd_config
GatewayPorts yes
[root@publicserver]# /etc/init.d/ssh restart
[root@publicserver]# netstat -antup | grep 8080
tcp   0   0 0.0.0.0:8080   0.0.0.0:*   LISTEN   15311/sshd: root

Now if someone on the internet points their browser to publicserver.org on port 8080, will get redirected through the SSH tunnel and securely connect to our home server behind the NAT.

Using SSH as a SOCKS Proxy

SOCKS defines a standard mechanism for a client to connect to a server by way of a proxy. This can be accomploshed by using the -D option in ssh:
[root@laptop]# ssh -D 9999 user@publicserver.org -N -f

Now you can configure your SOCKS aware program to connect to localhost on port 9999 and the traffic will be securely proxied through publicserver.org.
[root@laptop]# curl --socks5 localhost:9999 www.linux-admins.net