服务器上有些程序会优先走 IPv6,临时想让它走 IPv4,可以先从程序自己的设置里改。如果程序没有这个选项,也可以从系统这边处理。记一下两种办法,方便之后恢复。
动手之前,先确认自己是用 IPv4 连上服务器的,免得把自己关在外面。ip -4 addr 只能看到服务器有没有 IPv4 地址,不能证明当前 SSH 走的是 IPv4。在当前 SSH 会话中可以看一下:
echo "$SSH_CONNECTION"
输出依次是客户端地址、客户端端口、服务器地址、服务器端口,第三项是这次连接使用的服务器地址。确认是 IPv4,并且能重新登录,再继续。
方案一:用 sysctl 临时禁用
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
需要恢复时,把值改回 0:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=0
这里按原来两项都是 0 来写,动手前最好先查一下原值。禁用会移除接口上的 IPv6 地址和路由,重新启用也不等于原来的静态配置会完整回来,需要再检查。只执行 sysctl -w 没有写入配置文件,重启后是否启用,还是看系统原来的配置。
方案二:用防火墙拦住 IPv6 出口
如果只是临时拦住服务器本机程序的 IPv6 出口,也可以用 ip6tables。下面排除了 lo,保留本机 IPv6 回环通信:
sudo ip6tables -I OUTPUT 1 ! -o lo \
-j REJECT --reject-with icmp6-addr-unreachable
恢复时,删除刚加的这条规则:
sudo ip6tables -D OUTPUT ! -o lo \
-j REJECT --reject-with icmp6-addr-unreachable
添加命令执行一次就够了,重复执行会叠加规则,删除一次也只会删掉一条。这条规则还会拦住本机发往外部的 IPv6 回包,所以通过 IPv6 访问服务器上的服务也会受影响。Docker 容器等转发流量通常走 FORWARD,不能指望这一条把它们也管住。
用完再恢复
改完后让相关程序重新连接。如果它支持 IPv4 回退,才可能改走 IPv4;只支持 IPv6 的目标,拦住之后就连不上了。恢复后也要检查实际连接,不只是看命令有没有执行成功。
sysctl 的值可能被网络管理服务重新设置,但不能简单归因于 DHCP 续租。防火墙规则也可能在重启、重载防火墙或其他服务改规则时消失,谈不上哪个一定更稳定。临时处理选自己方便恢复的办法就行,只针对一个程序时,还是优先改那个程序。