Simple example of SSH tunneling

By | January 28, 2020

SSH tunneling is a technique to transfer arbitrary networking data using an encrypted SSH connection. It can be used to add encryption to not secure protocols such as HTTP and to bypassing firewalls. It is also named as port forwarding, there is a post related to C# implementation of SSH port forwarding.
Here is presented an example how to get access via SSH to blocked HTTP port plus transporting HTTP data in encrypted way. We have 2 machines A and B. The machine B has running HTTP and SSH servers. The machine A is Linux box which can connect to machine B via SSH but cannot sends HTTP requests to machine B because port 80 is blocked by firewall.
A and B machines
HTTP requests from A maching to B one are rejected:


# curl -I http://10.19.69.2
curl: (7) couldn’t connect to host



Let us create tunnel on machine A to transfer HTTP data tom machine A via SSH protocol:


# ssh -f -L 8888:localhost:80 root@10.19.69.2 -N
root@10.19.69.2's password: xxxxx

Now machine A has listening 8888 ports for IPv4 and IPv6 loopback addresses: 127.0.0.1 and ::1:


# netstat -a -n -p | grep 8888
tcp   0   0 127.0.0.1:8888   0.0.0.0:*   LISTEN 15981/ssh
tcp   0   0 ::1:8888         :::*        LISTEN 15981/ssh

and this listening port was opened by process with PID=15981:


# ps -ef | grep 15981
root 15981 1 0 08:38 ? 00:00:00 ssh -f -L 8888:localhost:80 root@10.19.69.2 -N

Now let us send HTTP HEAD request to local port 8888:


# curl -I http://127.0.0.1:8888
HTTP/1.1 200 OK
Date: Tue, 28 Jan 2020 14:57:26 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Mon, 27 Jan 2020 16:49:16 GMT
ETag: "160096-2c-59d21e3517f9e"
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html; charset=UTF-8

and it works.
This request also visible in Apache log file on machine B. However sshd server which receives request from machine A redirects in to IPv6 loopback address instead of IPv4 one:


# tail -n 1 /var/log/httpd/access_log
::1 - - [28/Jan/2020:10:07:26 -0500] "HEAD / HTTP/1.1" 200 - "-" "curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

Let us send HTTP GET request to local port 8888:


# curl http://127.0.0.1:8888
<html>
<body>
<h1>Test</h1>
</body>
</html>

It also works.
Form /var/log/httpd/access_log on B machine:


# tail -n 1 /var/log/httpd/access_log
::1 - - [28/Jan/2020:10:09:02 -0500] "GET / HTTP/1.1" 200 44 "-" "curl/7.19.7 (i386-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

Now repeating the same for IPv6 loopback:


# curl -I -g -6 "http://[::1]:8888"
HTTP/1.1 200 OK
Date: Tue, 28 Jan 2020 16:09:23 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Mon, 27 Jan 2020 16:49:16 GMT
ETag: "160096-2c-59d21e3517f9e"
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html; charset=UTF-8

curl -g -6 "http://[::1]:8888"
<html>
<body>
<h1>Test</h1>
</body>
</html>

Now lat us shut down the tunnel. From previous ps command output we now that ssh process with opened the tunnel has PID=15981. Let us kill this process and check 8888 port status:


# kill 15981
# netstat -a -n -p | grep 8888
#

There is no listening 8888 port so HTTP requests to 127.0.0.1:8888 does not work anymore.


# curl -I http://127.0.0.1:8888
curl: (7) couldn't connect to host

If HTTP server was configured for virtual hosting and runs several name-based web sites for the same IP address, the Host header with site name should be added to the HTTP request.

Leave a Reply

Your email address will not be published. Required fields are marked *