16

Linux 网络工具中的瑞士军刀 - socat & netcat

 4 years ago
source link: https://ryan4yin.space/posts/socat-netcat/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

文中的命令均在 macOS Big Sur 和 Opensuse Tumbleweed 上测试通过

socat & netcat

netcat(network cat) 是一个历史悠久的网络工具包,被称作 TCP/IP 的瑞士军刀,各大 Linux 发行版都有默认安装 openbsd 版本的 netcat,它的命令行名称为 nc.

而 socat(socket cat),官方文档描述它是 "netcat++" (extended design, new implementation),项目比较活跃,kubernetes-client(kubectl) 底层就是使用的它做各种流量转发。

在不方便安装 socat 的环境中,我们可以使用系统自带的 netcat. 而在其他环境,可以考虑优先使用 socat.

socat 的基本命令格式:

socat [参数] 地址1 地址2

给 socat 提供两个地址,socat 干的活就是把两个地址的流对接起来。左边地址的输出传给右边,同时又把右边地址的输出传给左边,也就是一个双向的数据管道

听起来好像没啥特别的,但是实际上计算机网络干的活也就是数据传输而已,却影响了整个世界,不可小觑它的功能。

socat 支持非常多的地址类型:-/stdio,TCP, TCP-LISTEN, UDP, UDP-LISTEN, OPEN, EXEC, SOCKS, PROXY 等等,可用于端口监听、链接,文件和进程读写,代理桥接等等。

socat 的功能就是这么简单,命令行参数也很简洁,唯一需要花点精力学习的就是它各种地址的定义和搭配写法。

而 netcat 定义貌似没这么严谨,可以简单的理解为网络版的 cat 命令 2333

二、安装方法

各发行版都自带 netcat,包名通常为 nc-openbsd,因此这里只介绍 socat 的安装方法:

# Debian/Ubuntu
sudo apt install socat

# CentOS/RedHat
sudo yum install socat

# macOS
brew install socat

其他发行版基本也都可以使用包管理器安装 socat

三、常用命令

1. 网络调试

1.1 检测远程端口的可连接性(确认防火墙没问题)

以前你可能学过如何用 telnet 来做这项测试,不过现在很多发行版基本都不自带 telnet 了,还需要额外安装。 telnet 差不多已经快寿终正寝了,还是建议使用更专业的 socat/netcat

使用 socat/netcat 检测远程端口的可连接性:

# -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 测试本机端口是否能正常被外部访问(检测防火墙、路由)

在本机监听一个 TCP 端口,接收到的内容传到 stdout,同时将 stdin 的输入传给客户端:

# 服务端启动命令,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

UDP 协议的测试也非常类似,使用 netcat 的示例如下:

# 服务端,只监听 ipv4
nc -u -l 8080

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

使用 socat 的 UDP 测试示例如下:

socat UDP-LISTEN:7000 -

socat UDP:192.168.31.123:7000 -

1.3 调试 TLS 协议

参考 socat 官方文档:Securing Traffic Between two Socat Instances Using SSL

测试证书及私钥的生成参见 TLS 协议、TLS 证书、TLS 证书的配置方法、TLS 加密的破解手段

模拟一个 mTLS 服务器,监听 4433 端口,接收到的数据同样输出到 stdout:

# 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

上面的命令使用了 mTLS 双向认证的协议,可通过设定 verify=0 来关掉客户端认证,示例如下:


# 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. 数据传输

通常传输文件时,我都习惯使用 scp/ssh/rsync,但是 socat 其实也可以传输文件。

以将 demo.tar.gz 从主机 A 发送到主机 B 为例, 首先在数据发送方 A 执行如下命令:

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

然后在数据接收方 B 执行如下命令,就能把文件接收到:

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

使用 netcat 也可以实现数据传输:

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

3. 担当临时的 web 服务器

使用 fork reuseaddr SYSTEM 三个命令,再用 systemd/supervisor 管理一下,就可以用几行命令实现一个简单的后台服务器。

下面的命令将监听 8080 端口,并将数据流和 web.py 的 stdio 连接起来,可以直接使用浏览器访问 http://<ip>:8080 来查看效果。

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

假设 web.py 的内容为:

print("hello world")

curl localhost:8080 就应该会输出 hello world

4. 端口转发

监听 8080 端口,建立该端口与 baidu.com:80 之间的双向管道:

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

拿 curl 命令测试一下,应该能正常访问到百度:

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

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK