隧道已经建立,IPv4 站点能打开,但有一个主机名超时。直觉结论是 VPN 坏了或凭据错了,通常两者都不成立。这个名字同时返回了 IPv4 和 IPv6 地址,应用挑了其中一个,而两个候选里只有一个路径是通的。做选择的是客户端;隧道只是没有覆盖它选中的那个地址。

选择并不等于覆盖承诺

RFC 6724 描述的默认地址选择,决定在多个候选可用时主机偏好哪一对源地址和目的地址。Happy Eyeballs 在其上增加连接策略:同时向两个地址族发起尝试,保留先应答的那个,用户无需等待坏掉的一族超时。

这两种机制都不创建路由。如果你的隧道只承载 IPv4,AAAA 候选仍然是客户端可以尝试的合法目的地址,失败表现为加载缓慢而不是报错,因为浏览器回退到了另一族。用户报告的是「网站慢」而不是「网站坏」,支持工单也继承了这种含糊。用固定地址族复现一次,报告就会变得具体。

正是这种回退让症状在不同应用间不一致。浏览器会掩盖延迟;固定地址族的命令行客户端会立刻把真实故障暴露出来。

确定请求实际使用了哪个地址族

从名字入手,而不是从隧道。查询两种记录类型,记下各自返回了什么:

dig +short A example.com
dig +short AAAA example.com
curl -4 -sS -o /dev/null -w '%{http_code}\n' https://example.com
curl -6 -sS -o /dev/null -w '%{http_code}\n' https://example.com

如果 v4 请求成功而 v6 请求失败,你就以可调试的形式复现了问题。如果命令行里两者都成功、浏览器仍然失败,先检查应用自己的解析器或缓存结果,再去动隧道。

把地址族和目的地址记进笔记。一张只说「网站通过 VPN 打不开」的工单谁都无法验证;而说清「AAAA 失败、A 正常」的工单,就指向了具体路由。

检查该地址族的路由

对失败的那一族,问内核它会走哪条路径,并与隧道配置的地址比对。在 Linux 上,ip -6 route get会显示该目的地址将选用的接口和源地址。

然后检查隧道本身。WireGuard 对端携带允许 IP 列表,而针对 0.0.0.0/0 的条目对 IPv6 只字未提。如果对端列表里没有 IPv6 前缀,客户端就没有理由把 AAAA 流量送进隧道,数据包会按主机原本的方式离开。

防火墙规则和 NAT 策略也值得按地址族分别检查。为 IPv4 写的规则在任何平台上都不覆盖 IPv6,这也是一个族能用、另一个族不能用的最常见原因。

不要为了截图好看而关闭 IPv6

在整个系统上关闭 IPv6 会让症状消失,同时让你失去诊断依据。它还会破坏任何只有 IPv6 的目的地,并把同一个 bug 藏起来留给下一个应用。如果一台机器确实不该使用 IPv6,那应当是有负责人、有测试的明确策略。故障处理期间关掉它,两者都不是。

想清楚客户端应该如何处理这一族,并显式配置:让它走隧道,或用受支持的方式阻断,使选择永远不会提供一个不可达的候选。两种都是合理设计。全局关闭两者都不是,因为它根本算不上设计。

工单里该写什么

记录四件事:主机名、失败的地址族、内核选择的路由,以及一次针对该族的请求结果。这组信息足以让他人复现故障,而不必猜你说的是两条路径中的哪一条。

RFC 6724 的地址选择规则解释了客户端为什么偏好它选中的候选,RFC 8305 则解释了掩盖延迟的竞速行为。它们都不会替你路由数据包,而这正是隧道必须承担的部分。

相关文章