机器一分钟前还在应答,VPN 一连上,同一个地址就超时了。三种故障都会造成这个现象,而且它们分处不同的机器。宿主机可能丢失了通往私网的路由,客户机的 NAT 网段可能与隧道现在通告的网段冲突,也可能整条全隧道接管了宿主机上的所有路由。动手改配置之前先查清是哪一种,因为每一种的修法都在别处。

看路由,别看机器

隧道起来时,看宿主机针对客户机地址的路由决策。仍然指向仅主机适配器的路由不是问题。现在指向 VPN 适配器的路由才是问题,而且改它的是客户端,不是你。适配器保住了地址,只说明接口活着,这和路径活着是两回事。

恰好在连接瞬间断掉的 SSH 会话是正常现象。客户端会循环使用适配器并写入路由,所以连接会死几秒。故障是再也回不来的那个连接,不是闪了一下的那个。

在隧道前后各抓一次表,然后对比这两份输出。差异就是诊断结论,也正好是网络负责人会索要的证据。

ip -4 route get 192.168.56.10
ip -brief addr show
ip route show table main | head -20

连接前后各读一次宿主机的表

在 Linux 上,重叠路由的优先级来自前缀长度和度量值,所以更具体的 VPN 路由即使错了也会赢。在 Windows 上由接口度量值决定平局,而隧道适配器通常带着比虚拟网卡更低的度量值出现。两种情况下的可见症状一样:数据包从隧道适配器出去,然后消失。

把适配器及其度量值打印在客户机前缀路由的旁边。这两份输出一眼就能回答归属问题。

Get-NetAdapter | Select-Object Name, InterfaceIndex, InterfaceMetric
Get-NetRoute -DestinationPrefix 192.168.56.0/24
route print -4 | Select-String '192.168.56'

如果路由变了但适配器的度量值没变,是客户端装了一条竞争路由。如果度量值变了,是客户端重排了适配器。两者都能修,而且修的地方不同。

当客户机的 NAT 网段就是冲突源

VirtualBox NAT 默认使用 10.0.2.0/24,而推送同一网段的隧道会让客户机把这份流量发往自己的 NAT 网关,而不是真正的目的地。数据包根本没离开宿主机,所以对端的任何防火墙日志都不会记录它。Docker Machine 的仅主机方案也有同类冲突,改动该方案可能需要连同证书一起重建机器。

选替换网段时,先列出隧道已经通告了什么,再列出办公网在用什么,最后列出这台宿主机上每个虚拟适配器占用了什么。破坏路由的是重叠,相不相像无关紧要。一个网段可以完全落在另一个里面,乍看却毫不相似。

在创建机器时就设定新网段,或者改完重新加载,然后从客户机侧再测一次失败的那个连接。真正重要的是客户机自己的表。

VBoxManage modifyvm devbox --natnet1 10.77.0.0/24
vagrant reload devbox --provision
vagrant ssh devbox -c 'ip route get 10.20.0.15'

恢复路径,别跟客户端硬碰

每个平台都提供了把仅主机前缀重新放回前面的办法。在 macOS 上,指向仅主机接口的静态路由撑到下次连接。在 Windows 上,把虚拟适配器的接口度量值调低就能保住优先。在 Linux 上,一次替换操作覆盖单个前缀。三者都是权宜之计,因为客户端一旦重申自己的路由就会把它们撤销。

把检查写成脚本,而不是开机时盲目重连。一个小脚本在每次连接后打印客户机前缀的路由,就把谜团变成日志里的一行。

如果配置文件是全隧道,就向网络负责人申请分流隧道或书面例外。悄悄加上绕过安全策略的路由不叫修复,那是第二个问题,而且会带着审计人员一起迟到。

两侧都验证一遍

改完之后验证三条路径:宿主机到客户机、客户机到公司主机、客户机到互联网。只恢复其中一条却破坏另一条的改动,是披着修复外衣的配置变更。把改动前采集的同一批输出再抓一次,比较才是同口径的。

把变动的接口、度量值和路由连同时间一起记下来,下次再出现就是查表,而不是重建。这条记录比一长串工单来回更值钱。

ip -4 route get 192.168.56.10
traceroute -n -m 4 10.20.0.15
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com

当宿主机又能到达客户机、客户机又能到达局域网时,你恢复的就是最初的那条路径。如果只有其中一条通,剩下的故障就在另一方的地盘上,而差异会告诉你那是哪块地盘。

相关文章