11 用nginx和socat实现ipv4与ipv6的转换

当服务器同时拥有公网ipv4和ipv6地址时,就可以将它配置为一台中转机,让纯ipv4环境的机器通过它实现对ipv6资源的访问(反之亦然)。

一、nginx:http/https端口转发

当ipv6资源是以http、https协议形式提供服务时,可以使用nginx来实现转发。

假设ipv4客户机是C,中转服务器是O,目标ipv6资源为D,由于O的nginx默认listen就是ipv4,因此无需任何特殊配置,直接使用proxy_pass即可。

如果反过来,想要让纯ipv6的客户机C,访问纯ipv4的资源D,则需要将listen行作一点点修改:

listen [::]:80 ipv6only=on;

[::]表示来源包括任意ipv6地址,:80表示监听80端口(通常用于http服务),ipv6only=on则明确要求listen开启ipv6模式。

至于proxy_pass,系统会自动解析目标地址,以确认它是一个ipv4地址,还是ipv6地址。

二、socat:其他协议转发

socat是linux下常用的网络工具,可以用来转发多种类型数据,典型的比如rdp。首先安装它:

sudo apt install socat

用它来执行数据转发:

socat TCP4-LISTEN:3389,fork TCP6:[ipv6-address]:3389
或
socat TCP4-LISTEN:3389,fork TCP6:ipv6-domain.com:3389

这行命令意思是在监听ipv4的3389端口,并将它转发到指定的ipv6地址或者域名对应的3389端口。

如果要反过来,只需要调换TCP4和TCP6即可。

socat命令不像windows那样持久生效,重启后如果不再次运行socat命令,则转发就停止了。可以用systemd来解决这个问题。在/etc/systemd/system/目录下,创建一个socat_config.service(文件名随意),内容如下:

[Unit]
Description=Socat TCP4 to TCP6 Forwarding(随意)
After=network.target

[Service]
ExecStart=/usr/bin/socat TCP4-LISTEN:3389,fork TCP6:myipv6site.com:3389
Restart=always
User=nobody
Group=nogroup
Environment="PATH=/usr/bin"
WorkingDirectory=/usr/bin

[Install]
WantedBy=multi-user.target

注意,这里指定了使用系统自带的nobody用户来执行,这是一个默认最小权限用户,可以确保它只用于转发流量,干不了别的。

然后刷新systemd配置,启用自启动服务,并启动服务:

sudo systemctl daemon-reload
sudo systemctl enable socat_config.service
sudo systemctl start socat_config.service

这时已经将该服务配置为开机自启。

但这个方法仍有一些瑕疵,ExecStart每次只能执行一条指令,如果需要映射多个端口就不行了。解决方法是新建一个sh脚本:

#!/bin/bash
//每行指定一个端口映射
/usr/bin/socat TCP4-LISTEN:3389,fork TCP6:mysite1.com:3389 &
/usr/bin/socat TCP4-LISTEN:3390,fork TCP6:mysite2.com:3390 &
//保持脚本运行,不退出
wait

注意,sh脚本的第一行“#!/bin/bash”不是注释,是指定了脚本的解释方式,切不可少了这一行。

sh脚本保存后,务必记得给它赋予执行权限:

chmod +x <.sh_PATH>

然后,将socat_config.service中的ExecStart的值,直接改为[.sh_PATH]即可,例如:

ExecStart=/usr/local/bin/socat_multiport.sh

然后systemctl restart socat_config.service重启服务。如果有问题,用systemctl status [服务名]查看服务状态。

最后,ufw防火墙记得放行Listen的端口,这个应该是常识咯。