In this tutorial, we’ll cover three tools for creating a tunnel from one local port to another in Linux. This is useful for situations like having a server for development where only some ports are accessible. In such cases, we may want to connect the traffic between a client and the localhost by tunneling between the internal open ports.
2. Examples Setup
The setup will be the same for all the three tools we’ll discuss.
We want to connect two ports in the local system. We’ll use port 8000 as the source for the connection and listen on port 8001.
By default, 127.0.0.1 is the address through which a system can talk to itself – it’s called the loopback address and is usually referred to as localhost. This is the address where our ports are located.
The first two solutions don’t require extra packages, as they rely on software bundled with Linux. However, the third approach requires the installation of additional software tools.
3. Using ncat
Currently, there are multiple implementations of the netcat application, but two of the most common ones are nc and ncat. All of them provide the same behavior. For the following code snippets, we will use the ncat utility.
Let’s setup the connection between the two ports:
$ ncat -l -p 8001 -c "ncat 127.0.0.1 8000"
To break down the command, we can see two calls to ncat. Let’s start with the one outside quotes. The flag -l asks to listen for incoming connections. The -p serves to specify the source port to be used, so we append it with 8001. Finally, the -c executes the provided command using the default shell.
The command between quotes connects to a server (given with its IP address) through the provided port. Thus, port 8001 will listen to the loopback address (127.0.0.1) at port 8000.
Moreover, as already discussed, we can replace the loopback address with localhost:
$ ncat -l -p 8001 -c "ncat localhost 8000"
This command will stop once we have performed a single remote connection. To keep it running, we can use the flag -k:
$ ncat -k -l -p 8001 -c "ncat localhost 8000"
The main drawback of this approach is that the connection is not encrypted, which may lead to security vulnerabilities if the transferred data is sensitive. If we want to avoid this, the next solution encrypts the tunnel without additional software.
4. Using ssh
Another solution to connect two local ports is using the ssh command.
We must ensure that, prior to the creation of the tunnel, the ssh daemon is running:
$ sudo systemctl start sshd
Once the daemon has started, we can create the tunnel between the two desired ports using ssh:
$ ssh -L 8001:localhost:8000 -N [email protected]
Let’s analyze the different parts of the command. The -L flag specifies the local client port on which the host, through its port, listens to. The format is port:host:hostport, which for our example is 8001:localhost:8000. The -N flag is especially suited for our purpose of port forwarding, as it doesn’t execute a remote command which would start a shell.
Finally, the [email protected] is required because it’s the part of the command that opens a connection via ssh. We used the current user variable $USER in the command because it improves the ease of use. Any other user that is available in the localhost is a valid option.
If we want to set the ssh in the background before executing any command, we can use the -f flag:
$ ssh -L 8001:localhost:8000 -f -N [email protected]
Even if ssh asks for passwords, the command will run in the background. It’s similar to the -k flag from ncat.
As before, we can replace localhost with the loopback address, achieving the same results:
$ ssh -L 8001:localhost:8000 -f -N [email protected]
In case we want that the listening port remains available for other network connections and is not restricted to connections originating in the localhost, we use the -g flag:
$ ssh -g -L 8001:localhost:8000 -f -N [email protected]
5. Using the socat Utilities
The third solution uses the socat utility, whose purpose is to establish a bidirectional connection.
The tool can handle many other types of sinks and sources of data apart from network ports, but we can use it for our problem of tunneling two local ports:
$ socat tcp-listen:8001 tcp:localhost:8000
The socat tool uses options that are provided with the command call. The first one, tcp-listen:port, states that the sink of the byte-stream will be a TCP (Transmission Control Protocol) connection through a port. This option includes both IPv4 and IPv6 addresses. If we only want one of them, either the tcp4-listen or tcp6-listen provides that functionality.
Finally, we need to specify the source of the byte-stream, which in our case is another TCP port. Thus, we use the option tcp:host:host-port. As before, we can restrict ourselves to IPv4 with tcp4:host:host-port and to IPv6 with tcp6:host:host-port.
When tunneling local ports, there are two features we are interested in. The first one is to keep the listening port available for other connections and not exclusively to the tunnel. For that, we have the option reuseaddr:
$ socat tcp-listen:8001,reuseaddr,fork tcp:localhost:8000
This option is usually coupled with the option fork to handle the channel of every connection as a child process.
The second feature is to keep the connection in the background. In contrast to the ssh method, there’s no option to directly set up the byte-stream in the background. Therefore we append & at the end of the command to start the process in the background:
$ socat tcp-listen:8001,reuseaddr,fork tcp:localhost:8000 &
Encryption can be used in tunnels created with socat, but the procedure is not as straightforward as that of ssh, so it’s outside of the scope of this article.
In this article, we’ve covered three ways of connecting two ports in the local system. We can follow this procedure to redirect traffic with either ncat, ssh, and socat, having a wide range of tools that we can use to connect these two ports.