连接后 VPN 路由度量变了:这意味着什么
更低的度量只在同等具体的路由之间打破平局。修改任何 VPN 路由号之前,先读策略规则、前缀和端点主机路由。
你连上 VPN,运行 route print,发现默认路由的度量比以前低了很多。最自然的结论是:因为它的数字更小,所以 VPN 抢走了默认路由。有时确实如此。但很多时候度量根本不是决定因素,改它什么也不会变,因为选择在更早的阶段就由前缀长度或策略规则做出了。
症状是真实的:原本从 Wi-Fi 适配器发出的流量现在走隧道,或者反过来。度量只是一次固定顺序查找中的一个输入,而你要读的正是那个顺序,然后才去动数字。
这个数字究竟在和什么竞争
第一步比较的是具体性,而不是优先级。10.20.0.0/16 的路由胜过 10.0.0.0/8,两者又都胜过 0.0.0.0/0,无论它们的度量是多少。一个在机器上安装最低度量默认路由的 VPN,仍然会输给任何与目的地匹配的更具体路由,包括客户端为自己服务器安装的那条主机路由。
这就是为什么调低默认路由的度量无法把 直连子网 推进隧道。若想让该子网进入 VPN,应为其前缀添加路由,或用策略规则选择隧道的表。度量这件工具用错了地方。
| Check in this order | Question | Where you read it |
|---|---|---|
| 1. Policy and table | Which routing table does this traffic use? | ip rule, client profile |
| 2. Prefix length | Which matching route is most specific? | route print, ip route |
| 3. Metric | Which of the equally specific routes is preferred? | route print, ip route |
| 4. Interface state | Is the chosen next hop reachable? | adapter status, link state |
Linux 先决定用哪张表,再谈度量
在 Linux 上,内核首先查询策略数据库。ip rule 列出规则及其选中的表,ip route get 203.0.113.10 报告内核针对该目的地实际会使用的表、路由和源地址。表 100 内的度量永远不会与主表中的路由竞争,因为规则在比较任何度量之前就已经选定了表。
所以一条路由可能在 ip route show table all 里看起来正确,却仍然不承载流量。先读匹配到的规则,再读它选中的表,然后比较表中的路由。如果选错了表,改另一张表里的度量不会有任何帮助。
Windows 把两个度量合并起来
Windows 默认没有策略数据库,但它会把路由度量和接口度量合并,而自动接口度量会随链路速度和适配器状态变化。这就是为什么同一个路由在出现扩展坞或虚拟适配器之后行为会不同。Find-NetRoute -RemoteIPAddress 203.0.113.10 报告所选的源地址、下一跳和接口,比原始表更接近真实决策。
把路由值和接口值放在一起读。提高接口度量可以在任何路由条目都不变的情况下移动流量,而 拥有自己路由的 VPN 客户端会在重连时重新安装它们,把你的修改丢掉。
让隧道端点待在隧道之外
每条隧道都需要一条不经过隧道的、通往自身服务器的路径。客户端会通过物理网关为端点安装一条主机路由,这条路由必须始终比客户端添加的默认路由更具体。删掉它,或者让隧道在查该地址时胜出,封装后的数据包就会试图进入它们本该建立的隧道。连接会失败或形成环路。
在改动度量前后都要检查那条主机路由:它应指向物理下一跳,并在重连后仍然存在。如果它归客户端所有,应修改配置文件或受管配置,而不是修改稍后会被覆盖的运行时值。
两类地址族和应用程序上下文都要检查
IPv4 和 IPv6 是各自独立的决策,各有自己的表。VPN 可以承载 IPv4,而 IPv6 继续走本地路由器;一个地址族里的度量变化说明不了另一个。两者都要检查,然后再检查应用程序上下文。绑定到某个接口的进程、容器命名空间或按应用划分的 VPN,看到的表可能和你的 shell 不同。
用能针对真实目的地报告决策的工具来验证,而不是看整张表的列表。如果选中的路由正是设计意图所在,就停手。屏幕上不是最小数字的度量并不是故障,强行把它改成最小,反而可能弄断隧道所依赖的端点路径。