Socat 端口转发:在 OpenWrt 上把 TCP/UDP 转明白

AI 摘要997笔记AI

socat可在OpenWrt上实现灵活端口转发,支持TCP、UDP、串口等地址间中继,弥补iptables跨协议转发不足;教程讲解安装、常用写法、调试参数、procd自启和防火墙放行,并指出其性能不及DNAT,更适合跨协议与临时调试场景。

此内容由AI根据文章内容自动生成。
Socat 端口转发:在 OpenWrt 上把 TCP/UDP 转明白

路由器上要做端口转发,很多人第一反应是防火墙的「端口转发」页面。但对一些特殊场景——跨协议、串口、临时调试——内核转发就不好使了,这时候 socat 才是顺手的工具。

这篇教程从 socat 是什么讲起,把 OpenWrt 上的安装、常用写法、开机自启和踩坑点一次讲透,所有命令都在 OpenWrt 24.10.5 上实测过。

一、socat 到底是什么

socat 的全称是 SOcket CAT,一个双向数据中继工具。你可以把它理解成「netcat 的加强版」:nc 主要用来读写 TCP/UDP,而 socat 能在几乎任意两种「地址类型」之间搭桥。

它支持的地址类型包括:

类型 写法 说明
TCP TCP:1.2.3.4:80 客户端连接
TCP 监听 TCP-LISTEN:8080 服务端监听
UDP UDP:1.2.3.4:53 UDP 客户端
UDP 监听 UDP-LISTEN:5353 UDP 服务端
Unix Socket UNIX-CONNECT:/var/run/x.sock 本机进程通信
串口 OPEN:/dev/ttyUSB0 串口设备
执行命令 EXEC:cmd / SYSTEM:cmd 把命令的输入输出当数据流
TLS OPENSSL:host:443 加密链路

只要两端是上面任意一种,socat 就能把它们接起来。这个能力决定了它和 iptables 的根本区别。

二、和 iptables 端口转发的区别

这是最容易搞混的地方,先讲清楚再动手。

对比项 iptables/nftables DNAT socat
工作位置 内核 netfilter 用户态进程
性能 极高,几乎无损 中等,每连接一个进程
协议转换 只能同协议 TCP ↔ UDP 可以互转
能看到内容 看不到 可以 -v 打印流量
配置位置 防火墙规则 命令行 + 服务脚本
掉线影响 无进程,永远在 进程挂了就不转
适合场景 大流量端口映射 跨协议、串口、临时调试

一句话总结:要跑满带宽用 DNAT,要灵活用 socat。

三、在 OpenWrt 上安装

SSH 登录路由器,两条命令:

opkg update
opkg install socat

实测环境是 OpenWrt 24.10.5(x86_64),安装过程很干净:

Installing socat (1.8.0.3-r2) to root...
Downloading .../socat_1.8.0.3-r2_x86_64.ipk
Configuring socat.

验证一下:

socat -V
# socat version 1.8.0.3 on 22 Oct 2026 21:58:03

体积和内存占用都不大:

项目 实测值
二进制大小 304.9 KB(/usr/bin/socat)
常驻内存 RSS 876 KB
依赖 无额外依赖包

在一台 512MB 内存的路由器上跑几个转发实例,完全感觉不到。

四、五种最常用的写法

1. 最经典的 TCP 转发

socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.100:80

意思是:监听本机 8080,每来一个连接就转发到 192.168.1.100 的 80 端口。

2. UDP 转发

socat UDP-LISTEN:5353,fork,reuseaddr UDP:192.168.1.100:53

注意 UDP 也必须加 fork,否则只能服务一个客户端。

3. TCP 转 UDP

这是 socat 最有价值的能力,iptables 做不到:

socat TCP-LISTEN:5300,fork,reuseaddr UDP:192.168.1.100:53

客户端用 TCP 连 5300,socat 帮你换成 UDP 去问 DNS。

4. 串口转 TCP

socat TCP-LISTEN:2000,fork,reuseaddr OPEN:/dev/ttyUSB0,raw,echo=0,b115200

把串口设备(交换机、单片机、光猫 console)挂到网络上,用 telnet 就能连。

5. 本机 Unix Socket 暴露成 TCP

socat TCP-LISTEN:9000,fork,reuseaddr UNIX-CONNECT:/var/run/docker.sock

五、参数逐个说清楚

参数 作用 什么时候必须加
fork 每个连接 fork 一个子进程 要支持多客户端,几乎必加
reuseaddr 允许绑定处于 TIME_WAIT 的端口 服务重启时避免报错
nofork 只服务一个连接就退出 临时调试
-d -d -d 日志详细程度(越多越详细) 排查连不上的问题
-v 打印双向流量内容 看数据到底通没通
-lh 把地址解析成可读格式 日志可读性
range=1.2.3.4/32 限制来源 IP 安全加固

调试时的标准姿势是三层日志加流量打印:

socat -d -d -d -v TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.100:80

日志会直接打在前台,能明确告诉你「监听成功没有」「对端连上没连上」。

六、让转发开机自启(procd)

命令行跑的 socat 一关 SSH 就没了。OpenWrt 用 procd 管理服务,写法如下。

新建 /etc/init.d/socat-nas:

#!/bin/sh /etc/rc.common
USE_PROCD=1
START=95
STOP=10

start_service() {
	procd_open_instance
	procd_set_param command /usr/bin/socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.100:80
	procd_set_param respawn 3600 5 0
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_close_instance
}

授权并启用:

chmod +x /etc/init.d/socat-nas
/etc/init.d/socat-nas enable
/etc/init.d/socat-nas start
/etc/init.d/socat-nas status

实测这套模板在 24.10 上直接可用:

status → running
netstat -ltnp | grep 8080
tcp  0  0  0.0.0.0:8080  0.0.0.0:*  LISTEN  5442/socat
curl 转发后返回 http=200

几个参数的含义:

  • respawn 3600 5 0:进程挂掉后 5 秒内最多重启 5 次,超过就停止(防止死循环刷日志)
  • stdout 1 / stderr 1:把输出交给系统日志,用 logread 能看

查日志:

logread -e socat | tail -20

如果只是临时用,也可以塞进 /etc/rc.local 的 exit 0 之前,但不推荐长期这么干——没有进程守护,挂了不会自己起来。

七、别忘了防火墙放行

socat 只是监听,能不能连进来由防火墙决定。OpenWrt 默认的 input 策略是 REJECT,所以你监听了 8080,从外面照样连不上。

命令行加规则:

uci add firewall rule
uci set firewall.@rule[-1].name='Allow-socat-8080'
uci set firewall.@rule[-1].src='lan'
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].dest_port='8080'
uci set firewall.@rule[-1].target='ACCEPT'
uci commit firewall
/etc/init.d/firewall reload

src 一定要写具体的区域(lan / wan),不要把 wan 直接放行,那等于把服务暴露到公网。

八、性能边界要说清楚

socat 是用户态转发,数据要从内核态拷到用户态再拷回去,中间还多一次进程调度。这意味着:

  • 单连接吞吐主要受单核性能限制,一般跑不满千兆
  • 并发连接多时,每个 fork 出来的子进程都占一份资源
  • 万兆环境完全不适合,应该用 nftables DNAT

所以正确的用法是分工:

场景 推荐方案
内网大文件传输、媒体流 nftables DNAT
管理端口(Web、SSH、串口) socat
TCP ↔ UDP 转换 socat(唯一选择)
临时抓包调试 socat -v
低频访问的小服务 socat

拿 socat 传 4K 视频流是自找麻烦,用它转发 NAS 管理页面就很合适。

九、六个常见坑

1. 端口被占用

netstat -ltnp | grep 8080

先看是谁占了,再决定换端口还是杀进程。

2. 重启时报 Address already in use

上一轮的连接还在 TIME_WAIT。加 reuseaddr 就能解决,这也是它几乎必加的原因。

3. OpenWrt 没有 pkill

busybox 精简掉了 pkill,习惯性敲会报 not found。改用:

kill $(pgrep socat)

4. EXEC 里写重定向不生效

EXEC:"dd ... 2>/dev/null" 不会按你预期工作,因为 EXEC 不经过 shell,重定向符号会被当成参数。需要 shell 特性就用 SYSTEM::

socat TCP-LISTEN:9000,fork,reuseaddr SYSTEM:"dd if=/dev/zero bs=64k count=100 2>/dev/null"

5. 连不上但进程在

九成是防火墙没放行,剩下一成是监听地址写成了 127.0.0.1。用 netstat -ltnp 确认监听的是 0.0.0.0 还是 127.0.0.1。

6. 进程越积越多

fork 模式下每个连接一个子进程,正常。但如果客户端异常断开后子进程不回收,检查是不是漏了 reuseaddr 或者对端把连接挂死了。ps w | grep socat 能看出一堆僵尸体。

十、卸载与清理

停用并删除自建服务:

/etc/init.d/socat-nas stop
/etc/init.d/socat-nas disable
rm /etc/init.d/socat-nas

卸载软件包:

opkg remove socat

结语

socat 的定位很清晰:它不是用来替代防火墙端口转发的,而是补上内核转发做不到的那些场景。

跨协议、串口、临时调试、低频管理端口,这四类需求用 socat 几分钟就能搞定;而需要跑满带宽的大流量,老老实实用 nftables DNAT。

装完之后体积 300 KB、内存不到 1 MB,几乎可以无脑装一台在路由器上备用——真遇到需要的时候,能省下不少折腾。

上一篇 群晖公钥私钥登录SSH的教程