How to perform a local ssh port forwarding in Linux

SSH supports a variety of ways of moving data across psuedo-VPN tunnel. One of the methods is Port Forwarding which creates a secure connection between a local computer and a remote machine through wich data can be transferred through an encrypted tunnel.
IMPORTANT NOTE:

This article is outdated, please follow How to configure SSH port forwarding (Tunneling) in Linux

 

Types of Port Forwarding

There are 3 types of Port Forwarding which can be performed on Linux namely

  • Local
  • Remote
  • Dynamic

 

Features

  • Tunneling support - psuedo-VPN for moving data
  • Tunnels local port(s) to remote systems for use by local system users
  • SSHD binds to a local port and provides access to a remote port
  • Default port forwarding binds to loopback addresses for IPv4(127.0.0.1) and IPv6(::1)
  • Ability to forward local ports to destination server via a third server.

Lets suppose we want to protect to access of telnet daemon on machine1. Since telnet is controlled by xinetd so we will force telnet to instead of binding to all IP addresses on all network interfaces only to bind to local loopback address.
Make sure you have telnet-server installed

# rpm -qa | grep telnet-server

If not you can install using yum

# yum -y install telnet-server

Next lets bind telnet to loopback address (on machine1)

# vi /etc/xinetd.d/telnet
service telnet
{
        flags           = REUSE
        socket_type     = stream
        wait            = no
        user            = root
        server          = /usr/sbin/in.telnetd
        log_on_failure  += USERID
        disable         = no
        bind            = 127.0.0.1
}
[root@machine1 ~]# /etc/init.d/xinetd restart
Stopping xinetd:                                           [  OK  ]
Starting xinetd:                                           [  OK  ]

Let us verify if we can telnet locally which we can also check using netstat

[root@machine1 ~]# netstat -ntlp | grep 23
tcp        0      0 127.0.0.1:23                0.0.0.0:*        LISTEN      3405/xinetd

So we should be able to telnet our localhost on port 23

# telnet localhost 23
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
CentOS release 6.5 (Final)
Kernel 2.6.32-431.el6.x86_64 on an x86_64
login: deepak
Password: [Password for deepak]

As you see I was able to login using my system's credential locally but what if I try to do the same from remote machine.
Lets try to telnet machine1 from machine 2 on port 23

[root@machine2 ~]# telnet machine1 23
Trying 192.168.1.11...
telnet: connect to address 192.168.1.11: No route to host
telnet: Unable to connect to remote host: No route to host

It didn't worked out too well since we have bind the telnet requests to loopback address
Now lets use ssh to encrypt a tunnel between client and out server
 

How it works

ssh_client -> ssh_server - to create encrypted tunnels

We will bind to a port like 2323 and forward that through the ssh tunnel to the remote system port 23 all bound to the loopback adapter. So locally we are connecting to the 2323 which a local socket so in case there is a trojan binary that functions as a network sniffer in the network then it will be able to pickup these type of connection but it won't be able to make out the data which goes inside the VPN tunnel.
local(127.0.0.1:2323) -> SSH_TUNNEL -> Remote(127.0.0.1:23)

Syntax:

ssh -L ip_address:2222:destination_system:destination_port user@gateway

We will leave the ip_address field blank and let ssh determine itself to use the default ip address bound to our ethernet card i.e. eth0 using the gateway of 192.168.1.12
lets take an example. We are going to bound the port 2323 locally to port 23 using a gateway i.e. machine2

# ssh -L 2323:127.0.0.1:23 machine2

NOTE: We donot need to be root to perform this action unless the port we are going to use requires root level privilege i.e. (< 1024) also known as well-known ports.

[root@machine1 ~]# ssh -L 2323:127.0.0.1:23 machine2
Last login: Fri Oct  3 05:30:26 2014 from machine1
[root@machine2 ~]#

So we are on machine2. Now lets attempt to connect out telnet client using new port 2323 from machine1

[root@machine1 ~]# telnet localhost 2323
Trying ::1...
Connected to localhost.
Escape character is '^]'.
CentOS release 5.2 (Final)
Kernel 2.6.18-92.el5 on an i686
login: deepak
Password:
Last login: Fri Oct  3 05:31:09 from machine1
[deepak@machine2 ~]$

As yo see I provided my user credential and even though I tried logging into localhost I connected to machine2. So as long as the ssh session is in place we ran earlier the VPN session will the alive.
 
Related Articles:
How to create password less ssh connection for multiple non-root users
Iptables rules to allow/block ssh incoming/outgoing connection in Linux
Putty session disconnects when idle