共计 4341 个字符,预计需要花费 11 分钟才能阅读完成。
背景
之前写过一篇 端口转发之 nginx (一),用于解决公司内网环境下的 tcp 端口转发问题。
实际使用后,发现存在一些不太令人满意的地方:
- 不会保留日志
- 性能偏弱
- 四层转发的配置不够灵活
同时,我近期购买了一台国内大带宽服务器A,同时我还有一台海外服务器B。为了解决直连B网络不佳的问题,我会用A来进行中转,即实现
用户 –> A ip:port
–> B ip:port
,需要能够同时转发 tcp 和 udp 包。
基于此,我了解到了 socat ,可以很好的解决当前问题。
socat 是什么
Socat(SOcket CAT)是一个功能强大的网络工具,用于在两个不同的数据流之间建立连接。它可以创建虚拟串口、连接网络套接字、进行数据转发和调试等操作。Socat是在UNIX和类UNIX系统上使用的开源软件,可以在命令行中使用。
Socat的主要功能包括:
- 建立连接:Socat可以在不同的网络套接字之间建立连接。它支持TCP、UDP、IPv4、IPv6等协议,并且可以在不同的主机之间进行连接。并且几乎没有连接数的限制。
- 数据转发:Socat可以将数据从一个数据流转发到另一个数据流。它可以在本地主机上进行转发,也可以在远程主机之间进行转发。这使得它在网络调试和数据重定向方面非常有用。
- 虚拟串口:Socat可以创建虚拟串口,使得应用程序可以通过串口与其他设备进行通信。这对于模拟串口设备或与硬件设备进行交互非常有用。
- 加密和认证:Socat支持使用SSL和TLS加密协议进行连接,并且可以进行客户端和服务器的身份验证。这使得它在安全通信方面非常有用。
- 端口扫描:Socat可以用于扫描主机上的端口,以确定哪些端口处于打开状态。这对于网络安全测试和漏洞评估非常有用。
Socat的命令行语法非常灵活,可以根据具体的需求进行配置。它提供了丰富的选项和参数,可以用于控制连接的行为和属性。Socat还支持脚本编程,可以编写复杂的连接脚本和数据处理逻辑。
实操
socat 的安装和配置转发极其便捷。
安装 socat
操作系统: Ubuntu 20.04
# 安装
apt-get install socat -y
# 查看版本
# socat -V
socat by Gerhard Rieger and contributors - see www.dest-unreach.org
socat version 1.7.3.3 on Oct 26 2019 17:42:04
...
配置转发
需要更复杂的转发场景,可以执行 socat -h
查看支持的选项和参数,下面介绍如何在IPV4场景下进行 tcp & udp 端口转发,例如将本机的 9999 端口 转发至远端IP的9999端口。
TCP 转发示例
socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:远端IP:9999
UDP 转发示例
socat -T 600 UDP4-LISTEN:9999,reuseaddr,fork UDP4:远端IP:9999
参数说明
- TCP4-LISTEN:本地被转发的tcp4端口
- UDP4-LISTEN:本地被转发的udp4端口
- reuseaddr:允许本地端口地址重用
- fork:将 Socat 进程转变为守护进程,并在接收到连接时创建子进程处理连接
- TCP4:远端IP 和 tcp端口
- UDP4:远端IP 和 udp端口
使用 supervisor 管理 socat
执行上述命令后,进程将会被前台执行以实现端口转发。实际使用时,我们肯定期望后台运行它。
后台运行有很多种方式,例如使用nohup,或者screen。在网上查阅文章时,大部分文章都介绍这两种方式,但是我并不建议,最简单的理由就是这两种方式不够稳定。如果进程中断后,将无法再次自动拉起。
有思考过使用 systemd 来进行管理,最后发现它也不是合适的方式。为什么?
socat 原生不支持多端口或端口段转发,每条转发规则仅允许单对单执行,那么我刚才的两条规则,就需要写两个 systemd 单元,会极大增加维护的成本,得不偿失。
最终,我选择使用 supervisor 对 socat 进行管理。
# 安装 supervisor
apt install supervisor
# 编辑 supervisor 配置文件,请将 远端IP 替换为实际的IP
# vim /etc/supervisor/conf.d/socat.conf
[program:socat_tcp]
command=socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:远端IP:9999
autostart=true
autorestart=true
stderr_logfile=/var/log/socat_tcp.err.log
stdout_logfile=/var/log/socat_tcp.out.log
[program:socat_udp]
command=socat -T 600 UDP4-LISTEN:9999,reuseaddr,fork UDP4:远端IP:9999
autostart=true
autorestart=true
stderr_logfile=/var/log/socat_udp.err.log
stdout_logfile=/var/log/socat_udp.out.log
# 启动 supervisor
systemctl start supervisor
# 查看 supervisor 状态
# systemctl status supervisor
# supervisorctl
socat_tcp RUNNING pid 247013, uptime 0:01:38
socat_udp RUNNING pid 247014, uptime 0:01:38
在使用包管理器安装 supervisor 后,默认会配置开启自启,无需额外配置。可以看看它的配置文件
- autostart=true
- autorestart=true
# cat /etc/supervisor/supervisord.conf
; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
autostart=true
autorestart=true
...
我们可以再看看 socat 启动的进程:
# ps -ef|grep socat
root 228688 1 0 14:23 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 245720 1 0 17:33 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 246206 1 0 17:45 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 246852 1 0 18:02 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 246901 1 0 18:04 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 246920 1 0 18:05 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 246984 1 0 18:07 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247013 247011 0 18:08 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247014 247011 0 18:08 ? 00:00:00 socat -T 600 UDP4-LISTEN:9999,reuseaddr,fork UDP4:1.1.1.1:9999
root 247140 247013 0 18:09 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247175 247013 0 18:10 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247235 247013 0 18:12 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247242 247013 0 18:12 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247260 247013 0 18:13 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247261 247013 0 18:13 ? 00:00:00 socat TCP4-LISTEN:9999,reuseaddr,fork TCP4:1.1.1.1:9999
root 247277 246427 0 18:14 pts/0 00:00:00 grep --color=auto socat
至此,所有配置完毕。
结论
socat 在实际使用中,配置简单且灵活,对于四层转发场景是一个很好的解决手段。
但是它仍有一个不太方便的点:
由于socat运行在用户态,无法实现批量的端口转发,例如它不能做到批量转发本地的10000~20000端口到 远端。只能每条命令启动一个socat进程,每个socat进程实现单个端口转发。
如果有这种需求,可以使用运行在内核态的 iptables 来实现,下篇文章再来进行介绍。