接收计数停在零而发送计数持续增长,描述的只是方向,不是诊断。同样的读数会出现在多种情况下:对端从未完成握手、目标选错了对端、远端没有回程路由,或者某个过滤规则在回程路上丢掉了回复。这几种情况需要在完全不同的地方修复。

能缩短排查的对比只有一种:请求到底有没有离开隧道,回程到底有没有回来。在正确的接口上抓一次包,就能在两者之间做出判断。

计数只说明流量,不说明故障方向

WireGuard 的计数记录接口交给对端多少字节、又从对端收到多少字节。它不会说明是哪个目标、哪个对端或者交换的哪一半出了问题。背景流量还会让总数更不可靠,因为其中一些字节可能是保活报文或无关的连接。把它当作接口仍在工作的提示,然后就不要再当作证据。

第一个有用的事实是握手是否还在有效期内。没有握手,就没有任何数据为这个对端加密,接收计数也没有理由变化。

对端选择与回程路径:两种解释

第一种解释是数据包从未到达预期的对端,因为路由指向了别处,或对端允许的前缀没有覆盖该目标。第二种解释是数据包到了,但回程出不来,这属于远端自己的路由问题。下表按每种观测现象区分这两类情况。

ObservationPoints to
No handshake while transmit climbsPeer selection or endpoint
Handshake current, request visible on the serverReply path or far-side route
Request never visible on the serverAllowed prefixes or local route
Both packets visible, nothing reaches the clientReturn filter or translation

从表的顶部往下读。没有握手,就先查密钥、端点和外层路径,因为此时还没有别的东西可查。握手有效且服务器上能看到请求,问题就转到回程方向,由目标自己的路由表决定。请求在服务器上根本不出现,则是选择问题,那就要先比较两侧允许的前缀。

这四行里有两行在客户端修,两行在服务器修。判断自己属于哪一对,就是大部分工作量。

回复消失在哪里

回复离开目标,到达服务器的隧道接口,然后按允许地址匹配客户端内网地址的对端来加密。如果这个匹配不成立,回复会被静默丢弃,从客户端看和网络故障一模一样。如果回复已加密,却被客户端自己的过滤规则拒绝,症状同样完全一样。这两种情况都需要抓包,而不是看计数。

最典型的一种是服务器替客户端转发数据包,却没有回到客户端内网网段的路由。它接受请求,把回复发向自己的默认网关,隧道里再也看不到这个包。在服务器上加一条范围很宽的转换规则,只会掩盖这个问题,而不会修好路由。

把一个目标从端到端测通

在对端网段里只选一个目标,并在握手明确有效时进行测试。下面的命令会读取对端状态、选中的路由以及交换的两侧。抓包要放在加密数据包实际使用的接口上。

wg show wg0 latest-handshakes
wg show wg0 transfer
ip route get 10.60.9.5
sudo tcpdump -ni wg0 host 10.60.9.5

如果抓包显示请求出现在隧道接口上、却没有任何回程,那就是服务器一侧的答案,接下来该看目标的路由表。如果什么也看不到,说明数据包走了另一条路,那么本地路由才是嫌疑对象。两个抓包里都能看到交换、但应用没有进展,问题就转向数据包大小,或转向接口统计里根本看不到的过滤规则。测试时只保留一个目标和一个客户端,因为多一个变量就会把证据变回感觉。

如果名称解析失败而某个允许的地址可用,答案在 DNS 而不是隧道里。如果只有大流量卡住,那要单独检查数据包大小。

相关文章