WireGuard 握手成功,却没有回复返回
最近的一次握手证明密钥是通的。先跟踪一个内网地址并读取传输计数器,再考虑怪罪隧道、固件或密钥。
最近的握手是好消息,但它比人们想写的那句话所声称的要小得多。双方交换了通过认证的握手消息。应用数据包仍然必须抵达内网目的地并返回。
健康的控制面与沉默的数据面之间的这道鸿沟,正是本文的全部主题。对同一组计数器读两次,你就能知道自己站在哪一边。
握手证明的是密钥,不是投递
WireGuard 握手是带认证的密钥协商。只要双方能互相到达并持有有效密钥,它就会成功。而路由、防火墙策略以及目的地本身,都是握手从来不问的问题。
因此隧道可以建立得完美无缺,而其中的每个数据包都被丢弃。路由错误的内网数据包与走另一条路的回复,从客户端看完全一样。
一个内网地址就是全部测试
选定一个目的地并一直用它。对端自己的隧道地址是最简单的情形,而对端后面的主机正好多出一跳。在两者之间来回切换却不记录变化,得到的是一组没人能比较的结果。
接着看客户端选择的路由。更具体的本地路由可能在系统询问 WireGuard 之前就把数据包送到别处,只要家庭 LAN 与远端网段重叠,这种情况就会出现。
ip route get 10.30.8.10
ip -4 addr show wg0
ip route show table all | grep -w wg0
解析到物理网卡的地址已经回答了这个问题。隧道没有丢弃任何东西。数据包从未进入隧道。
计数器是证据,不是判决
wg show 会报告每个对端发送和接收的字节数,而这两个数字是独立变化的。先读一次,做一次被允许的请求,然后在同一分钟内再读一次。
wg show wg0 transfer
wg show wg0 latest-handshakes
ping -c 4 10.30.8.10
wg show wg0 transfer
接收不动而发送在涨,就是请求没有得到回复的特征。它不能说明请求是否被过滤、目的地是否宕机、或者回复是否走了另一条路由。这是三个共享同一症状的排查方向。改动任何配置之前,先把它们分开。
固定的字节数也不是成功的门槛。计数器数值随流量变化,把某一个数字当作健康证明,只会得到自信的胡话。
对端会自己检查返回的数据包
远端只有在源地址落在它自己的 allowedips 之内时才接受内网数据包。发送端存在一条路由并不够。接收端缺少源地址条目,就会悄无声息地丢弃返回流量。
主机防火墙就挡在那道检查之后。一条只放行隧道接口、不放行内网子网的转发规则,会接受握手却拒绝数据包。从客户端看,这和一端彻底死掉一模一样。双网卡的主机还可能从错误的源地址回应,于是对端丢掉了它从未预料到的回复。
让实验保持诚实
在它本该到达的那张家庭网络里测试远程访问配置,走的是与预期不同的路径。换到外部网络,并记录它的本地前缀,这样两次运行才能比较。
一次小的成功交互也不能排除所有路径问题。较大的数据包可能在小包能通过的地方失败,而按大小或协议匹配的过滤器在负载下可能表现不同。
把握手当作已知可用的阶段,从这里往前走。下一个有用的证据是某一次内网请求停在哪里,而不是换一套新密钥再猜一轮。