1. Overview

In this tutorial, we’ll take a look at the socat command in Linux. Socat is a flexible, multi-purpose relay tool. Its purpose is to establish a relationship between two data sources, where each data source can be a file, a Unix socket, UDP, TCP, or standard input.

2. Use Case of socat

Socat is useful for connecting applications inside separate boxes. Imagine we have Box A and Box B, and inside Box A, there’s a database server application running. Furthermore, Box A is closed to the public, but Box B is open. Our network will allow a connection from Box B to Box A.

Now, let’s say a user wants to read the database log. We don’t want the user to enter Box A, but we’re fine if the user wants to get inside Box B.

Socat can connect the database log in Box A with a text reader in Box B. That way, the user can read the log in Box B. We don’t have to compromise the security of Box A in order for the user to do the job.

Socat can work in both directions. The user in Box B might want to send some database queries to the database server application in Box A. Then, the database server application could send the result back to the user in Box B. Socat supports two-way communication as well.

Let’s start with an introduction to the socat command. Then, we’ll continue with a series of examples.

3. Installing socat

Socat is available in most Linux distros.

3.1. Prerequisites

For the examples in this tutorial, we’ll use nc and Docker, which we can install from their user guides.

3.2. Installing socat in Debian-Based Linux

To install socat on Debian-based Linux (such as Ubuntu), we use apt-get:

$ apt-get install -y socat

3.3. Installing socat in RHEL-Based Linux

On RHEL-based Linux (such as Fedora), we should use yum:

$ yum install -y socat

4. Bidirectional Stream

We can use socat to connect two data sources and stream data between them.

4.1. Connecting Two Stream Sources

Let’s connect nc with the Transmission Control Protocol (TCP) and stream data from both directions. We’ll need two console terminals to conduct this experiment.

On the first terminal, let’s run nc in listening mode:

$ nc -l localhost 1234 

The -l flag indicates nc is in the listening mode. It listens on localhost port 1234.

On the second terminal, let’s run socat to connect STDIO to localhost with port 1234 using the TCP protocol:

$ socat STDIO TCP4:localhost:1234

In the command above, the first argument is the standard input, represented with the keyword STDIO. The second argument is a string with a special syntax. As we can see, the string is divided into three parts with a colon delimiter. The first part is the address format, TCP4. The second part is the server or the IP address, localhost. The last part is the port, 1234.

The socat application connects the stream from the first argument (STDIO) to the one mentioned in the second argument (TCP4:localhost:1234). In this case, we can switch the order of the arguments and it doesn’t matter because it’s bidirectional.

4.2. Testing the Streams

Now, our standard input on the second terminal is connected to the nc server. We can type something on it:

Good morning!

Then, we go back to the first terminal. We can see that the text we typed on the second terminal was printed on the first terminal:

Good morning!

Then, we can type something below “Good morning!” on the first terminal:

Life is beautiful.

Then, we go back to the second terminal. We can see that “Life is beautiful.” was printed there as well:

Life is beautiful.

4.3. Forwarding a Stream

Instead of handling the data itself, socat can forward the data that will be received by another socat application. This time, we need three console terminals.

On the first terminal, we run nc as usual:

$ nc -l localhost 1234

On the second terminal, we run socat. But this time, we don’t connect the standard input with the nc application on the first terminal. Instead, we listen on another port:

$ socat TCP4-LISTEN:4321 TCP4:localhost:1234

We used a different string syntax, TCP4-LISTEN:4321. It means we listen to the data that comes from the second argument, TCP4:localhost:1234, and write it to port 4321. When we used the TCP4-LISTEN address format, we only added the port. This is different from the TCP4 address format where we have to fill the server address.

On the third terminal, we’ll run socat, and this time, we connect the standard input to the socat application on the second terminal:

$ socat STDIO TCP4:localhost:4321 

Now, when we type something on the first terminal, we can see the text appear on the third terminal. The three terminals are networked via the second terminal acting as a relay.

4.4. Connecting Docker with socat

To make our example more practical, we’ll connect the webserver in a separate terminal with a web client. First, we need to pull the Nginx Docker image:

$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
1fe172e4850f: Pull complete 
35c195f487df: Pull complete 
213b9b16f495: Pull complete 
a8172d9e19b9: Pull complete 
f5eee2cb2150: Pull complete 
93e404ba8667: Pull complete 
Digest: sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

We make sure port 80 is not occupied. Then, we run the nginx Docker image:

$ docker run -p 80:80 nginx

The run argument is to run the Docker image. The -p option maps port 80 on the container to port 80 on the host. If we didn’t do this, we wouldn’t be able to access the webserver from the host.

Then, on the second terminal, we run socat to connect to the Nginx server:

$ socat TCP-LISTEN:1234,reuseaddr,fork TCP:localhost:80

We’ve learned the first argument previously. TCP-LISTEN is to listen to data movement in port 1234. But here, there are other parts in the argument syntax: reuseaddr and fork. They mean that socat will fork a child process to processes connecting to this port.

On the third terminal, let’s run socat to connect the standard input to port 1234:

$ socat STDIO TCP4:localhost:1234

Finally, in the fourth terminal, let’s run the same command again:

$ socat STDIO TCP4:localhost:1234

Notice that we’re connecting two socat applications to the same port. This works because we use reuseaddr and fork in the TCP-LISTEN argument. If we didn’t use them, the same command on the fourth terminal would fail:

$ 2022/04/14 02:37:17 socat[4017376] E connect(5, AF=2 127.0.0.1:1234, 16): Connection refused

We can type anything to test the connection. We can do this on the third terminal or on the fourth terminal. Let’s test the web connection. We can use GET request:

GET /

We’ll get the output in the same terminal:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</html>

On the first terminal, we can see that socat passed the data just fine:

172.17.0.1 - - [28/Apr/2022:16:51:34 +0000] "GET /" 200 615 "-" "-" "-"

5. Unidirectional Stream

We’ve learned that socat is a bidirectional stream protocol by default. But we can use its unidirectional mode.

5.1. The -u Flag

We can create a file using socat. Let’s run the command below, type something, then press Enter, and finally exit:

$ socat -u STDIO FILE:test.txt,create
Hello socat!

We can check the content of the test.txt file:

$ cat test.txt
Hello socat!

The -u flag means that the stream of data runs from the first argument, STDIO, to the second argument, file text.txt. The second argument uses the FILE address format. As we can guess, this format accepts the name of the file and the mode of opening the file. In our example, the mode is create. There is no data streaming from the second stream to the first in this mode.

The order or arguments matters. If we switched the arguments, the result of the command would be different:

$ socat -u FILE:test.txt,create STDIO
Hello socat!

This time, the command displayed the content of the file. If we tried with a different and new file, the output would be empty:

$ socat -u FILE:baeldung.txt,create STDIO

When the first argument is the file, and STDIO is the second argument, socat reads the content of the file and displays it in the stdout. But when it’s in reverse, socat writes the input from stdin into the file.

5.2. The -U Flag

There’s another flag that does the reverse operation of the -u flag. The -U flag is the same as the -u flag but the order of the arguments is reversed.

Let’s run the previous command but with the -U flag, type something, then press Enter, and finally exit:

$ socat -U FILE:test.txt,create STDIO
Hello socat! This time we use the -U flag.

Then we can check the content of the file:

$ cat test.txt
Hello socat! This time we use the -U flag.

So basically, socat -u arg1 arg2 is the same as socat -U arg2 arg1.

6. Conclusion

In this article, we’ve introduced the command socat in the bidirectional mode. We started a series of examples by running nc and connecting to it using the TCP protocol and the standard input. Then, we verified that they could stream data between each other.

Additionally, we also connected the Docker container and the standard input using socat. Between them, we used the standard input and the TCP protocol.

Finally, we ran socat in unidirectional mode with the -u flag and the -U flag to read and write a file.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.