The commands in this article were tested on macOS Big Sur and Opensuse Tumbleweed

socat & netcat

netcat (network cat) is a long-established network toolkit, known as the Swiss Army knife of TCP/IP. All major Linux distributions have the openbsd version of netcat installed by default, and its command line name is nc .

And socat (socket cat), which is officially described as "netcat++" (extended design, new implementation), is a more active project, and is used by kubernetes-client (kubectl) to do all kinds of traffic forwarding.

In environments where it is not convenient to install socat, we can use the netcat that comes with the system. In other environments, we can consider using socat in preference.

1. Introduction

The basic command format of socat.

1
socat [参数] 地址1 地址2

The socat is provided with two addresses, and what the socat does is to dock the streams from the two addresses. The output of the left address is passed to the right, and the output of the right address is passed to the left, which is a bidirectional data pipeline.

It sounds like nothing special, but in fact, computer networks do the job of data transfer, but affect the whole world, and its function should not be underestimated.

socat supports a very large number of address types: - /stdio, TCP, TCP-LISTEN, UDP, UDP-LISTEN, OPEN, EXEC, SOCKS, PROXY, etc. It can be used for port listening, linking, file and process reading and writing, proxy bridging, etc.

The only thing you need to spend some effort to learn is the definition of the various addresses and how to write them.

The definition of netcat seems to be less strict, and can be simply understood as a network version of the cat command.

2. Installation method

Each distribution comes with netcat, usually named nc-openbsd, so only the installation of socat is described here.

1
2
3
4
5
6
7
8
# Debian/Ubuntu
sudo apt install socat

# CentOS/RedHat
sudo yum install socat

# macOS
brew install socat

Other distributions can basically install socat using the package manager

3. Common commands

1. network debugging

1.1 Test the connectivity of remote ports (make sure the firewall is OK)

You may have learned how to use telnet to do this test before, but nowadays many distributions basically don’t come with telnet anymore, and you need to install it additionally. telnet is almost at the end of its life, so it is recommended to use the more professional socat/netcat

Use socat/netcat to check the connectivity of remote ports.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# -d[ddd] 增加日志详细程度,-dd  Prints fatal, error, warning, and notice messages.
socat -dd - TCP:192.168.1.252:3306

# -v 显示详细信息
# -z 不发送数据,效果为立即关闭连接,快速得出结果
nc -vz 192.168.1.2 8080

# -vv 显示更详细的内容
# -w2 超时时间设为 2 秒
# 使用 nc 做简单的端口扫描
nc -vv -w2 -z 192.168.1.2 20-500

1.2 Test if the local port can be accessed externally properly (check firewall, routing)

Listen to a TCP port on the local machine and pass the received content to stdout, while passing the input from stdin to the client.

1
2
3
4
5
6
7
8
# 服务端启动命令,socat/nc 二选一
socat TCP-LISTEN:7000 -
# -l --listening
nc -l 7000

# 客户端连接命令,socat/nc 二选一
socat TCP:192.168.31.123:7000 -
nc 192.168.11.123 7000

The UDP protocol is tested very similarly, using the following example from netcat.

1
2
3
4
5
6
7
# 服务端,只监听 ipv4
nc -u -l 8080

# 客户端
nc -u 192.168.31.123 8080
# 客户端本机测试,注意 localhost 会被优先解析为 ipv6! 这会导致服务端(ipv4)的 nc 接收不到数据!
nc -u localhost 8080

An example of a UDP test using socat is as follows.

1
2
3
socat UDP-LISTEN:7000 -

socat UDP:192.168.31.123:7000 -

1.3 Debugging the TLS protocol

Refer to the official socat documentation: Securing Traffic Between two Socat Instances Using SSL

Simulate an mTLS server, listening on port 4433, and outputting the received data to stdout as follows

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# socat 需要使用同时包含证书和私钥的 pem 文件,生成方法如下
cat server.key server.crt > server.pem
cat client.key client.crt > client.pem

# 服务端启动命令
socat openssl-listen:4433,reuseaddr,cert=server.pem,cafile=client.crt -

# 客户端连接命令
socat - openssl-connect:192.168.31.123:4433,cert=client.pem,cafile=server.crt
# 或者使用 curl 连接(我们知道 ca.crt 和 server.crt 都能被用做 cacert/cafile)
curl -v --cacert ca.crt --cert client.crt --key client.key --tls-max 1.2 https://192.168.31.123:4433

The above command uses the mTLS two-way authentication protocol, and client authentication can be turned off by setting verify=0, as shown in the following example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

# socat 需要使用同时包含证书和私钥的 pem 文件,生成方法如下
cat server.key server.crt > server.pem

# 服务端启动命令
socat openssl-listen:4433,reuseaddr,cert=server.pem,verify=0 -

# 客户端连接命令,如果 ip/域名不受证书保护,就也需要添加 verify=0
socat - openssl-connect:192.168.31.123:4433,cafile=server.crt
# 或者使用 curl 连接,证书无效请添加 -k 跳过证书验证
curl -v --cacert server.crt https://192.168.31.123:4433

2. data transfer

Normally, I am used to using scp/ssh/rsync when transferring files, but socat can actually transfer files as well.

Take demo.tar.gz from host A to host B as an example, first execute the following command on the data sender A.

1
2
3
# -u 表示数据只从左边的地址单向传输给右边(socat 默认是一个双向管道)
# -U 和 -u 相反,数据只从右边单向传输给左边
socat -u open:demo.tar.gz tcp-listen:2000,reuseaddr

The file is then received at data recipient B by executing the following command.

1
2
3
socat -u tcp:192.168.1.252:2000 open:demo.tar.gz,create
# 如果觉得太繁琐,也可以直接通过 stdout 重定向
socat -u tcp:192.168.1.252:2000 - > demo.tar.gz

Data transfer is also possible with netcat.

1
2
3
4
# 先在接收方启动服务端
nc -l -p 8080 > demo.tar.gz
# 再在发送方启动客户端发送数据
nc 192.168.1.2 8080 < demo.tar.gz

3. Act as a temporary web server

With fork, reuseaddr and SYSTEM commands, and a bit of management with systemd / supervisor, you can implement a simple backend server with a few lines of commands.

The following command will listen on port 8080 and connect the data stream to web.py’s stdio, which can be accessed directly using a browser at http://<ip>:8080 to see the results.

1
socat TCP-LISTEN:8080,reuseaddr,fork SYSTEM:"python3 web.py"

Suppose the contents of web.py are

1
print("hello world")

Then curl localhost:8080 should output hello world

4. port forwarding

Listen to port 8080 and establish a two-way pipe between this port and baidu.com:80:

1
socat TCP-LISTEN:8080,fork,reuseaddr  TCP:baidu.com:80

Use the curl command to test it and you should be able to access Baidu properly at

1
2
# 注意指定 Host
curl -v -H 'Host: baidu.com' localhost:8080