端口转发是一个你不常会遇到的情况,但是一旦他来了,手头的工具要么太重,要么不趁手。举个简单的例子,你可能需要外网流量转发到本地内网,也有可能需要把IPv6流量转移到外网的IPv4,甚至可能需要UDP转发,面对这多样的情况,iptables
的性能上不去,配置太麻烦,后期维护不方便等等问题很容易成为阻碍。面对这样的情况,我们需要 socat
来解决这一切。
介绍&安装
netcat是个计算机网络公用程式,用来对网络连线TCP或者UDP进行读写。
socat 是 netcat 较复杂的姊妹程式。它比起netcat更大更复杂,并且有更多的选项得在给定作业前先设定。
事实上socat的功能非常强大,能做到的不仅仅是端口转发这样简单的事情。
安装没什么好说的
apt-get install socat
实践
要注意,socat只是一个命令行工具,要守护运行你可能需要nohup或者supervisor,这里着重介绍socat的参数与功能。
socat的上手难度并不高,你只需要记住这个固定的语法,就可以把参数和变量套进去,即
socat [options] <address> <address>
不要把 address
仅仅想成网络地址,由于Linux的万物皆文件,这里的 address
也可以是某个pipe或者某个文件。
一般来说,address
有这么几个常用的类型
- TCP/UDP:建立一个TCP/UDP连接作为数据流
- TCP-LISTEN/UDP-LISTEN:监听一个端口
- 文件:任意路径的文件
在地址后面可以加一些选项,这个我们放在后面详细说。
对于端口转发,我们需要监听一个地址,同时把监听到的数据发送给另外一个地址,这里就有了两个 address
类型,举例来说,就好比这样
socat TCP-LISTEN:8080 TCP:192.168.1.2:8080
这样我们就实现了监听本地8080端口,并将该端口的数据转发到192.168.1.2的对应端口上,socat
会自己帮我们把反向的链路建立,所以不需要类似 iptables
的多余操作。
正如前面所说,socat
是一个命令行程序,这就意味着他不能在同一个终端下建立多个进程,这对于高并发场景来说意味着多条TCP抢socat,延迟也会因此有着不可忍受的波动,所以我们使用 reuseaddr
参数绑定一个本地端口,同时使用 fork
参数将socat转变为多链接模式,即当一个链接建立后,自动复制一个同样的端口监听,这样就能有效提高高并发场景下的性能表现。
但是在实际的生产场景中,为了避免 root
用户执行某些程序,我们还要给 socat
指定一个运行权限。所以,最终是这个样子的
socat TCP-LISTEN:8080,reuseaddr,fork,su=nobody TCP:192.168.1.2:8080
这里你可以把TCP换成UDP或者简单的变为TCP6/UDP6,可以指定对应的协议进行监听和转发,或者可以只用TCP或者UDP,在 option
中使用 -4
或 -6
参数来指定偏好的协议。
特别的,对于UDP这样的链接来说,最好在命令中加入 -T
参数,尽快关闭不活跃的链接。
socat -T 120 UDP-LISTEN:8080,reuseaddr,fork,su=nobody UDP:192.168.1.2:8080
这样,在UDP链路不活跃120s之后,这个fork出来的子进程就会被关闭,但是主进程仍然保留。
进阶
由于 address
的变化性,我们甚至可以把 socat
作为Web Server或者一个文件服务器,
socat -d -d /dev/sda1,rawer,nonblock,ignoreeof,cr,echo=0 TCP-LISTEN:55555,reuseraddr
这样,一个监听在55555端口上的文件服务器就有了,其中
-d -d
:输出调试信息rawer
:直接读取/写入,这样可以提升速度。nonblock
:使用non-block IO模式防止拥塞ignoreeof
:忽略EOF,这让这台文件服务器一直在线,而不是每传输完一个文件后就关闭cr
:换行符转换ehco=0
:关闭echo(根据rawer的要求)
总之,你可以使用做端口转发,做文件服务器,做任何有关两点间通信的任何事情。