「正在断开连接」是客户端在拆除隧道时报告的状态,而不是「流量已停」的结论。在 Mac 上,这个拆除按一段很短的顺序推进,标签只有在拥有该连接的组件回报之后才会变化。当某一步在等辅助进程、插件或策略决定时,标签可能在接口已经消失后仍留在那里,也可能菜单还在显示它而隧道仍在转发。把这段文字当作「拆除进行中,结果未知」,并弄清哪一半才是真的。

两种故障从菜单栏上看一模一样,却需要相反的处置。一种情况下隧道仍在承载数据包,只有显示是陈旧的。另一种情况下隧道已经消失,但另一套策略仍在阻断流量——这往往是刻意为之。路由和 DNS 状态比任何菜单操作都能更快地把两者区分开。

标签在跟踪什么

VPN 客户端维护一个小小的状态机,菜单栏只是它的投影。对于由 macOS 自己管理的连接,这个状态机位于系统 VPN 框架中。对于由应用管理的隧道,它位于应用及其特权辅助进程中。停止的最后一步不是关闭套接字。而是释放让隧道得以工作的东西:utun 接口、指向它的路由、客户端注入的解析器条目,以及连接期间阻断流量的任何防火墙规则或策略。

这些步骤彼此独立,所以停止可能卡在任意一步。辅助进程不再应答、第二条接口也认领同一条路由,或者解析器条目归属另一个配置,都可能让客户端一直等待。标签只报告客户端自身的进度,因此它在意图上可信,在网络实况上并不可靠。

找出拥有该连接的组件

对于原生配置,scutil --nc list 会列出系统已知的服务及其状态,scutil --nc status "Work VPN" 给出单个服务的详情。 由第三方应用持有的隧道可能根本不出现在那份列表里因此结果为空并不能证明没有连接。

如果配置属于某个应用,就以该应用的状态视图和它文档中写明的「断开连接」控件为准。关闭窗口并不是停止请求——只要后台辅助进程持有隧道,图标消失而辅助进程仍让接口保持活着。Apple 的 VPN 设置参考 介绍了原生控件以及受管理设置的来源。

读接口、路由和 DNS

三项检查无需触碰连接就能回答大部分问题。关键在于把它们放在一起解读,因为任何单项单独看都会误导。

scutil --nc list
netstat -rn -f inet | head -20
ifconfig | grep -A 3 '^utun'
scutil --dns | head -30
  • 存在 utun 接口,默认路由或分流路由经过它,解析器指向服务商:隧道仍在运行,标签已陈旧。
  • 没有 utun,普通默认路由,DNS 来自 DHCP,无法上网:断开时阻断流量的策略正在生效。
  • 没有 utun,没有路由,解析器仍指向服务商:拆除停在半途,DNS 就是需要清掉的残留。

然后向内网主机(只应经由隧道应答)和公网主机各发一个请求。可达性把策略和残留状态区分开,而不必把检查变成测量练习。如果路径仍有响应,先保存远程工作;在一台你远程管理的机器上改动网络之前,先准备好第二条进入通道。

为什么大范围杀进程和删除配置会误导

像 pppd、racoon 和 configd 这样的进程名属于特定实现。杀掉它们可能影响其他连接,留下路由和 utun 接口,也不会留下究竟卡在哪一步的记录。旧的进程名同样不能证明它持有当前配置。

删除并重建配置是比清理一次卡住的过渡更大的动作。它可能在说不清哪里失败的情况下丢弃受管理设置和本地身份材料;在受监管的 Mac 上,配置还可能被直接恢复。把删除留给真正过时的配置,改为诊断这个过渡。

留下痕迹的停止顺序

下面的顺序让连接自身的控件保持主导,并在卡顿复现时留下记录。它也能避免你把显示问题变成网络改动。

  1. 保存远程工作;如果 Mac 是远程的,确认你还能从另一条路径到达它。
  2. 记下客户端名称、版本和配置。用 log show --last 5m --predicate 'subsystem == "com.apple.networkextension"' 抓取一小段窗口;较旧的版本保留的历史更少,所以要在卡顿后尽快执行。
  3. 使用文档中写明的「断开连接」控件,等待,然后重复接口和路由检查。
  4. 如果标签陈旧但隧道已经掉下来,就让它留着,让客户端自己刷新,而不是强行结束进程。
  5. 如果拆除真的卡住了,重启客户端;在工作保存之后再计划重启 Mac。受管理机器需要走管理员流程。

恢复之后,确认普通默认路由和 DHCP 解析器已回来,并且被阻断的流量要么恢复、要么是刻意继续阻断。把配置和客户端版本连同症状一起记下,这样下一次就能从证据出发,而不是靠对菜单栏的猜测。

相关文章