Have you ever had a headache finding a solution to connect to an unreachable computer, which is behind the router and you do not have permission to configure NAT? If the answer is yes, this article is for you.

Contents

1. Problem

Juleit

I need your help, Dr. Weird!

Dr. Weird

Alright. What can I do for you, Juleit?

Juleit

I want to make a good meal to treat my lover, Moreo, but I do not know how to cook. Can you come here and do it for me, please?

Dr. Weird

Hmmm. Okay. I do not cook well, but I will try. Give me your address.

Juleit

Oops! You cannot go through the front door of my house because it is heavily guarded by The Router. He never allows anyone to visit me without my father’s permission.

Dr. Weird

Okay, so even if I know your home address, I cannot reach out to you, right?

Juleit

I have to admit that. Is there any other way, Dr. Weird?

Dr. Weird

Umm, yes! Although you are in an unreachable place, I can still reach out to you using the SSH Tunneling method.

Juleit

Cool! What is it?

Dr. Weird

Magic!

Juleit

Wow! Can that magic also bring Moreo here, Dr. Weird?

Dr. Weird

Yep!

2. SSH tunneling

Vuong

Dr. Weird, let me explain to readers about this method. I do not want your storyline to be ruined.

Dr. Weird

Thank you, I am grateful!

Vuong

My pleasure!

SSH tunneling, or SSH port forwarding, is a method of forwarding networking data over an SSH channel between an SSH client machine’s and an SSH server machine’s ports.

There are three types of port forwarding: local port forwarding, remote port forwarding, and dynamic port forwarding depending on the direction of data forwarding.

Method #1: Local port forwarding

Local Port Forwarding

Local Port Forwarding

Local Port Forwarding (External Server)

Local Port Forwarding (External Server)

The SSH client machine creates a local socket to listen to a local port. Any traffic data that comes to this port is forwarded to the SSH server machine before being forwarded to the destination machine. The destination machine can be the SSH server machine or another machine.

Typical use cases:

  • Connecting to an external service on the remote machine
  • Connecting to a protected service on the destination machine through the remote machine, for example, the destination machine only allows access from the remote machine

The SSH command:

$ ssh -L [<local-ip>:]<local-port>:<destination-ip>:<destination-port> [email protected]

Where:

  • <local-ip>: the optional binding address on the local machine
  • <local-port>: the listening port number on the local machine
  • <destination-ip>: the destination IP address
  • <destination-port>: the destination port number

Method #2: Remote port forwarding

Remote Port Forwarding

Remote Port Forwarding

Remote Port Forwarding (External Server)

Remote Port Forwarding (External Server)

How the remote port forwarding method works is the opposite of the local port forwarding method.

The SSH client machine creates a socket on the SSH server machine to listen to a server port. Any traffic data that comes to this port is forwarded to the SSH client machine before being forwarded to the destination machine. The destination machine can be the SSH client machine or another machine.

The typical use case is providing access to an internal service on the local machine from the outside.

The SSH command:

$ ssh -R [<remote-ip>:]<remote-port>:<destination-ip>:<destination-port> [email protected]

Where:

  • <remote-ip>: the optional binding address on the remote machine
  • <remote-port>: the listening port number on the remote machine
  • <destination-ip>: the destination IP address
  • <destination-port>: the destination port number

Method #3: Dynamic port forwarding

Dynamic Port Forwarding

Dynamic Port Forwarding

It is almost the same as the local port forwarding method except the destination machines are dynamic instead of fixed. This turns the SSH server into a SOCKS proxy server (the SOCKS4 and SOCKS5 protocols are supported).

The SSH command:

$ ssh -D [<local-ip>:]<local-port> [email protected]

Where:

  • <local-ip>: the optional binding address on the local machine
  • <local-port>: the listening port number on the local machine

3. Use cases

Use case #1: Accessing an unreachable machine from a public machine

Dr. Weird (5678) ----- Juleit (22)

Back to the story above, to let Dr. Weird’s machine access Juleit’s machine, Juleit has to use the remote port forwarding method by opening a socket on Dr. Weird’s machine to listen to his port number 5678 then forward traffic data from this port back to her local port number 22 (SSH server).

juleit:~$ ssh -N -R 5678:localhost:22 [email protected]

Note that I used the -N option here to tell the SSH client not to execute any remote commands after authenticating successfully.

Then, Dr. Weird can access Juleit’s machine via her SSH service from his local port number 5678.

drweird:~$ ssh -p 5678 [email protected]

Done!

Use case #2: Accessing an unreachable machine from another unreachable machine

Moreo (1234) ----- Dr. Weird (5678) ----- Juleit (22)

Back to the story above, again, Moreo wants to access Juleit’s machine through Dr. Weird’s machine, the only public machine here. It is very simple by bridging 2 tunnels: one from Moreo’s machine to Dr. Weird’s machine and the other from Dr. Weird’s machine to Juleit’s machine.

To create the former, Moreo will use the local port forwarding method by opening a local socket to listen to his local port number 1234 then forward traffic data from this port to Dr. Weird’s port number 5678.

moreo:~$ ssh -N -L 1234:localhost:5678 [email protected]

The latter I have just created in the above example:

juleit:~$ ssh -N -R 5678:localhost:22 [email protected]

Then, Moreo can access Juleit’s machine via her SSH service from his local port number 1234.

moreo:~$ ssh -p 1234 [email protected]

Done again!

Use case #3: Accessing the internet via a SOCKS proxy

You can use the dynamic port forwarding method to create a SOCKS proxy via an SSH channel.

Moreo (1234) ----- Dr. Weird ----- (the internet)

Let’s suppose Moreo wants to access the internet through Dr. Weird’s machine.

moreo:~$ ssh -N -D 1234 [email protected]

Then, Moreo can access the internet via a SOCKS server at localhost:1234 on his machine by any client, including web browsers.

I will show you how to verify that the proxy server works with cURL. In this case, I will use the ipinfo.io/ip endpoint to check the requested client IP address.

First, in Dr. Weird’s machine:

drweird:~$ curl ipinfo.io/ip
111.111.111.111

In Moreo’s machine:

# do not use the SOCKS proxy
moreo:~$ curl ipinfo.io/ip
222.222.222.222

# use the SOCKS proxy
moreo:~$ curl -x socks5://localhost:1234 ipinfo.io/ip
111.111.111.111

4. Conclusion

SSH tunneling is an amazing feature that helps you solve access related issues.

Here are 2 side notes that you should know.

First, when executing an SSH command, if you get the error: Too many authentication failures then you should try to add the option -o IdentitiesOnly=yes to that command. I suggest you read the article Best way to generate and manage SSH keys for more details.

Second, in this article, I use the SSH service with port number 22 as examples, but you can use the port forwarding methods for any service, including web services, database services, etc.