nc / socat —— 连通性测试与临时数据通道

运维工具手册 02-进程与网络诊断 5.6 KB 原文

nc / socat —— 连通性测试与临时数据通道

分类:02 进程与网络诊断 适用:Linux / macOS(nc 有 OpenBSD 与 traditional 两个变体,参数不同) 一句话:nc 测端口通不通、临时传文件;socat 做端口转发、协议转换、TLS 包装。

1. 它解决什么问题

  • 目标端口通不通(不等应用层健康检查)。
  • 两台机器之间临时传个文件,不想开 FTP/scp。
  • 临时把某端口转发到另一台机器(socat 更稳)。
  • 起一个裸 TCP/UDP 服务做联调。

2. 先确认你用的是哪个 nc

nc -h 2>&1 | head -5
readlink -f $(command -v nc)
变体 特征 常见系统
OpenBSD netcat -h 显示 OpenBSD netcat,支持 -z、-k、-N Ubuntu/Debian 默认 netcat-openbsd
traditional / GNU 支持 -e、-c,不支持 -z 在部分版本 CentOS 的 nc(nmap-ncat 或 nc)
nmap-ncat 支持 -z、--send-only、--recv-only RHEL 系装 nmap 时提供

参数差异会直接导致命令报错,先认清变体。

3. 安装

apt install -y netcat-openbsd socat
dnf install -y nmap-ncat socat
apk add netcat-openbsd socat

4. 端口连通性测试

nc -zv 10.0.0.5 3306              # 测 TCP(OpenBSD / nmap-ncat)
nc -zv -w 3 10.0.0.5 3306         # 3 秒超时
nc -zv 10.0.0.5 20-30             # 端口范围
nc -zuv 10.0.0.5 53               # 测 UDP
nc -zv -4 host 80                 # 强制 IPv4

输出:

Connection to 10.0.0.5 3306 port [tcp/mysql] succeeded!

traditional 版没有 -z,用:

nc -w 2 10.0.0.5 3306 < /dev/null && echo open || echo closed
timeout 2 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.5/3306' && echo open

/dev/tcp 是 bash 内建,任何有 bash 的机器都能用,最省事。

5. 临时传文件

接收端

nc -l 9000 > received.tar.gz          # OpenBSD:-l 直接跟端口
nc -l -p 9000 > received.tar.gz       # traditional:需 -p
nc -lk 9000                           # 持续监听(多连接,OpenBSD)

发送端

nc 10.0.0.5 9000 < file.tar.gz
tar czf - /data | nc 10.0.0.5 9000    # 边压边传

校验:

md5sum file.tar.gz
# 两端比对,避免传输截断

明文传输,不要用于敏感数据。跨公网用 scp/rsync/socat OPENSSL。

6. 起一个临时服务/客户端

# 服务端:任何连上来的请求都回一行
while true; do echo "HTTP/1.1 200 OK\r\n\r\nhello" | nc -l 8080; done

# 客户端手动说话(调试 SMTP/Redis 等文本协议)
nc 10.0.0.5 6379
PING
+ PONG

# 发原始 HTTP 请求(绕过 curl 的封装,看真实报文)
printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' | nc example.com 80

调试 Redis 时这招很好用:printf '*1\r\n$4\r\nPING\r\n' | nc host 6379。

7. socat:更强的转发与协议转换

socat 的模型是"两个地址之间的双向管道":socat <地址1> <地址2>。

端口转发(临时,替代 iptables)

# 本机 8080 → 内网 10.0.0.9:80
socat TCP-LISTEN:8080,fork,reuseaddr TCP:10.0.0.9:80

# 后台常驻
nohup socat -d -d TCP-LISTEN:8080,fork,reuseaddr TCP:10.0.0.9:80 >> /var/log/socat.log 2>&1 &
  • fork:每个连接 fork 一个子进程,必须加,否则只能服务一个连接。
  • reuseaddr:避免重启时 Address already in use。

连通性测试

socat - TCP:10.0.0.5:3306          # 连上就打通,Ctrl-C 退出
socat - UDP:10.0.0.5:53
echo | socat - TCP:10.0.0.5:80

监听并回显(联调用)

socat -v TCP-LISTEN:9000,fork -     # -v 打印双向数据
socat -x TCP-LISTEN:9000,fork -     # -x 十六进制

Unix socket 与 TCP 互转

socat UNIX-LISTEN:/tmp/app.sock,fork TCP:127.0.0.1:8080
socat TCP-LISTEN:8080,fork UNIX-CONNECT:/var/run/docker.sock

后者常用于把 Docker socket 暴露给需要 TCP 的工具(注意安全,等于给 root)。

TLS 包装

# 明文服务套一层 TLS
socat OPENSSL-LISTEN:8443,cert=/etc/ssl/server.crt,key=/etc/ssl/server.key,verify=0,reuseaddr,fork \
      TCP:127.0.0.1:8080

# 客户端连 TLS 后转本地明文
socat TCP-LISTEN:8080,fork,reuseaddr OPENSSL:remote.example.com:443,verify=1

串口/设备/文件

socat - /dev/ttyUSB0,b115200,raw,echo=0
socat FILE:/tmp/data.txt TCP-LISTEN:9000,reuseaddr

常用地址类型

地址 含义
TCP:host:port TCP 客户端
TCP-LISTEN:port,fork,reuseaddr TCP 服务端
UDP:host:port / UDP-LISTEN:port UDP
UNIX-CONNECT:path / UNIX-LISTEN:path 本地 socket
OPENSSL:host:port / OPENSSL-LISTEN:... TLS
EXEC:cmd 执行命令,stdin/stdout 接入管道
SYSTEM:cmd 同 EXEC,走 shell
FILE:path 文件
- 标准输入输出

8. 实战场景

8.1 防火墙规则验证(不依赖应用)

nc -zv -w 3 <ip> <port>
# 或者批量
for p in 22 80 443 3306 6379; do
  timeout 2 bash -c "cat < /dev/null > /dev/tcp/$IP/$p" 2>/dev/null \
    && echo "$p open" || echo "$p closed/filtered"
done

8.2 数据库端口通了但应用连不上

nc -zv 10.0.0.5 3306          # TCP 层通
socat - TCP:10.0.0.5:3306     # 能看到 MySQL 握手包开头(乱码即正常)

如果有握手包,说明网络没问题,问题在认证/权限/白名单。

8.3 临时把内网服务映射到跳板机

# 跳板机上
socat TCP-LISTEN:13306,fork,reuseaddr TCP:10.0.0.9:3306
# 本地连跳板机 13306 即可访问内网 MySQL

长期使用请用 SSH 隧道或 frp,socat 无认证、无加密。

8.4 抓明文协议交互

socat -v -x TCP-LISTEN:9000,fork TCP:10.0.0.9:80
# 客户端连 9000,-v 打印可读内容,-x 打印十六进制

9. 常见坑

  1. -l 与 -p 的差异:OpenBSD 用 nc -l 9000,traditional 用 nc -l -p 9000,混用会报错。
  2. -e 被大多数发行版移除:出于安全考虑(反弹 shell),需要自己编译或改用 socat EXEC:。
  3. 传文件后另一端没退出:加 -N(OpenBSD)让对端关闭时关闭 socket。
  4. socat 不加 fork 只能服务一个连接,第二个连接会挂起。
  5. socat 不加 reuseaddr 重启报端口占用。
  6. 明文无认证:nc/socat 转发等于把服务暴露给能访问该端口的所有人。
  7. UDP 测试不可靠:UDP 无连接,nc -zu 成功只代表发出了包,不代表对端处理。
  8. nc -z 会建立完整 TCP 连接(connect 扫描),会被目标记录日志。
  9. 容器内 socat 转发要监听 0.0.0.0,默认可能只绑 IPv6 或 localhost。
  10. socat 不支持多路复用高级特性,需要健康检查、负载均衡请用 nginx/haproxy。

10. 速查表

# nc
nc -zv <host> <port>                 # 测 TCP
nc -zv -w 3 <host> <port>            # 带超时
nc -zuv <host> 53                    # 测 UDP
nc -l 9000 > file                    # 接收(OpenBSD)
nc -l -p 9000 > file                 # 接收(traditional)
nc <host> 9000 < file                # 发送
nc <host> 6379                       # 手动对话

# bash 内建(无需装包)
timeout 2 bash -c 'cat < /dev/null > /dev/tcp/<host>/<port>' && echo open

# socat
socat - TCP:<host>:<port>                                  # 连通测试
socat TCP-LISTEN:8080,fork,reuseaddr TCP:<host>:<port>      # 转发
socat -v TCP-LISTEN:9000,fork -                             # 打印内容
socat TCP-LISTEN:8080,fork UNIX-CONNECT:/var/run/x.sock     # socket 转 TCP
socat OPENSSL-LISTEN:8443,cert=c.pem,key=k.pem,verify=0,reuseaddr,fork TCP:127.0.0.1:8080
nc / socat —— 连通性测试与临时数据通道 - 知识库 - 起航社区