WireGuard 握手成功却没有网络:逐个追踪一个数据包
握手只能证明密钥与可达性。从 AllowedIPs 出发,沿着转发、NAT 和返回路由追踪一个数据包,看它究竟停在哪里。
隧道已经起来,wg show 显示最近完成过一次握手,你能 ping 通服务器的隧道地址,可它之外的任何东西都不回应。第一反应往往是重新生成密钥或重新分享配置。这恰好改动了路径中已经被证明可用的那一段。
一次成功的握手只说明两端在密钥上达成一致、UDP 能到达端点、加密路由接受这个数据包。它完全不说明数据包随后能否离开服务器。
所以别再猜,去追踪一个数据包。它可能死掉的只有四个地方,每个地方留下的痕迹都不同。
握手到底证明了什么
WireGuard 是一种 UDP 协议:先用 Noise 握手建立会话,然后为对端加密数据包。当 wg show 显示几秒前的握手和不断增长的传输计数时,端点、密钥以及对端公钥全都是正确的。
它没有证明的是:你的客户端到底有没有把发往网络的流量送进接口,服务器愿不愿意转发,以及回应能不能找到回来的路。这些是内核路由和防火墙的决定,都在隧道之外完成。
这就是为什么 ping 服务器的隧道地址是一个极具误导性的测试。那个数据包 是发给服务器自己的,所以在本地就结束了。它永远不需要转发,不需要地址转换,也不需要来自网络的返回路由。
AllowedIPs 是一个路由决定
在客户端上,AllowedIPs 承担两个职责。它既是加密密钥路由表,决定哪些目标地址进入这个对端的隧道,又是对端愿意接受你哪些源地址的清单。如果客户端配置里只写了 10.8.0.0/24,公网目标就永远不会进入接口,你原来的默认路由会把它们带出隧道。这时隧道工作得完美无缺,却没做任何你想要的事。
看客户端实际装了什么,而不是配置里写了什么:
wg show wg0 allowed-ipsip route get 1.1.1.1
第二条命令才是决定性的。如果答案里出现你的物理接口和常规网关,说明数据包根本没被隧道接管,服务器端怎么改都无济于事。分别给 IPv4 加上 0.0.0.0/0,给 IPv6 加上 ::/0;只覆盖一族的通配规则会把另一族留在原路径上,这正是 IPv4 隧道能用而 IPv6 解析卡住的常见原因。
数据包在网关上死在哪里
如果路由正确而数据包仍然无处可去,说明它到了服务器就停住了。四项检查覆盖大多数网关。
转发。 sysctl net.ipv4.ip_forward 返回 0 是经典答案,很多发行版默认仍是 0。它必须是 1,而且要写进 sysctl 文件长期生效,而不是用一条重启就消失的命令。IPv6 转发是另一个开关。
过滤策略。 默认策略为 drop 的 FORWARD 链会丢掉隧道流量,却放行到主机自身的流量,这与症状完全吻合。要读正在生效的规则集,不是存盘文件:nft list ruleset 或 iptables -S。
地址转换还是路由。 使用私有隧道地址的客户端,要么在服务器出口接口上做源 NAT,要么使用上游网络知道如何回传的路由前缀。二者之间的选择取决于地址规划。给一个本来就会回传你前缀的网络再加 MASQUERADE 无害但无意义;而在没有路由的地方省掉它,回应就会指向一个不可路由的私有网段。
返回路径。 在路由式设计里,上游路由器需要一条指向你服务器的路由。云厂商的网络也可能拦下它:一些云在实例上开启了源/目的地址检查,会把源地址不是实例自身地址的数据包静默丢弃,直到你关掉这项检查。
DNS 的失败方式与路由不同
发往已知地址的数据包和域名解析是两种不同的故障,而报错信息会往相反方向误导你。如果 ping 1.1.1.1 能通而浏览器什么都打不开,那是路由没问题、解析有问题。如果 ping 本身就失败,DNS 就无关紧要,你该回到上一节。
wg-quick 可以从配置里的 DNS = 行设置解析服务器,而 systemd-resolved 对每个链路的处理又各不相同。一个用只能在隧道内访问的地址覆盖解析器的 VPN,会在隧道断开的瞬间让所有解析失败,看起来就像隧道把网络弄坏了。
| Symptom | Layer to inspect |
|---|---|
| Tunnel address pings, nothing else does | Client route, then gateway forwarding |
| Public IP pings, hostnames fail | Resolver selection and reachability |
| Handshake completes, no reply ever | FORWARD policy or missing NAT on the server |
| Small requests work, large transfers stall | MTU and TCP MSS clamping |
一个能产出证据的顺序
先跑客户端侧的检查,因为它只有一条命令,却能排除一半可能。然后确认服务器本来是否被设计成网络出口;为私有访问而建的网关,在公网目标不通时并不算坏。
在服务器上,一边从客户端发 ping,一边看接口:tcpdump -ni wg0 icmp 应该显示请求,tcpdump -ni eth0 icmp 应该显示它带着或不带转换地出去。如果只在前者出现、后者从未出现,问题就停在服务器本地。如果它出去了却没有回应回来,问题在上游,那是另一回事。
最后让修复扛住一次重启。转发应该写进 sysctl 文件,防火墙规则应该交给加载它们的服务,客户端路由应该放进把接口拉起来的配置,而不是一个你迟早会忘掉的 shell。重连、重跑同样两项测试,确认计数在动。