排障记录:wiregurad——外网ping不通内网网关
自上次建立了wireguard隧道,成功从外网访问到内网服务器之后,出现了一个新的问题——外网服务器只能访问内网服务器本身,而无法通过其访问内网其它设备,比如网关。
环境:
公网服务器10.8.0.1 阿里云
内网服务器10.8.0.2 ubuntu24.04
外网客户端10.8.0.3 windows10
内网网关 192.168.0.1
首先按照常规思路,为了让其它设备能访问内网网关,在内网服务器和公网服务器的wireguard配置中加入了192.168.0.0/24这个网段。
[Peer]
PublicKey = LBxXLKUiI6nA=
Endpoint = 公网服务器IP:51820
AllowedIPs = 10.8.0.0/24, 192.168.0.0/24 ##加入了这个网段
PersistentKeepalive = 25
启用这套配置之后,发现内网服务器自己也不能ping通192网关了,删除192.168.0.0/24之后恢复。
原理剖析:
AllowedIPs 在客户端的作用是路由表。当 Ubuntu 的 AllowedIPs 包含 192.168.0.0/24 时,wg-quick 会强行修改系统路由,把去往 192.168.0.1 的包塞进 wg0 虚拟隧道,导致路由环路,包出不去。
Ubuntu 本身不需要走隧道去访问192网关,它只需要负责“转发” Win10 的包,允许其进入隧道是大错特错。
转而第二种思路,在建立隧道之后,我们在外网客户端上执行了
route add 192.168.0.0 mask 255.255.255.0 10.8.0.2
这里的意思是将去往192.168的数据包指定下一跳路由是10.8.0.2
然后进行了tracert:

发现这个数据包确实到达了内网服务器,但是在内网服务器上丢失了,因此问题就出在内网服务器中。
顺带一提,在解决了这个问题之后,发现并不需要这么做,即便不进行route add,数据包的路径也是正常的。
在内网服务器里,查看 NAT 伪装规则的流量计数(-v 显示详细,-n 显示 IP 数字)
sudo iptables -t nat -L POSTROUTING -v -n
输出:

无论外网怎么ping 192.168.0.1,物理网卡(enp2s0)的pkts(包计数)始终不变,说明数据包根本没走到 NAT 这一步。
查看系统转发链的规则和默认策略
sudo iptables -L FORWARD -v -n

发现 Chain FORWARD (policy DROP),并且排在最前面的是 DOCKER-USER 链。
经查找,Ubuntu 上安装的 Docker 会修改 iptables 的 FORWARD 链,并强制将默认策略改为 DROP(拒绝所有转发)。从 wg0 进来的数据包,因为没有被明确放行,直接触底被 DROP 丢弃了。
解决方案:
在内网服务器的wiregurad配置文件[interface]底部,加入
PostUp = iptables -I DOCKER-USER -i wg0 -j ACCEPT; iptables -I DOCKER-USER -o wg0 -j ACCEPT
PostDown = iptables -D DOCKER-USER -i wg0 -j ACCEPT; iptables -D DOCKER-USER -o wg0 -j ACCEPT;
意思是在 DOCKER-USER 链插入放行 wg0 的规则,重启生效。
后续外网ping192.168.0.1可以通,虽然还是打不开网关管理界面,但那又涉及到MTU长度不匹配的问题了,本文不讨论,后续打算做反向代理。但无论怎么讲,现在算是真正打穿内网了。
浙公网安备 33010602011771号