要弄清断网开关是否守得住,你并不需要真实账户,被测试置于风险之中的恰恰就是账户。检查会制造一个短暂窗口,在此期间流量可能流出隧道,也可能不流出,所以载荷应当是可以舍弃的东西。我现在用一个诱饵页面和一个备用浏览器配置文件来做这件事,得到的答案比过去那套浏览器加网页邮件的做法更清楚。下面按照客户端呈现的顺序展开:设置、目标、切换,然后是证据。

这个测试只回答一个狭窄的问题:在这次切换期间,这个应用能否到达隧道之外的网络? 它并不说明其余策略是否合理。把范围保持得这么小,结果才值得写下来。

在客户端里找到开关及其作用范围

在改变任何网络状态之前,先打开客户端找到拦截设置。各家厂商的叫法不同:断网开关、锁定模式、网络锁、拦截隧道外的流量。标签能告诉你的,比它里面的选项少。关键在于拦截是始终生效,还是只在应用判定隧道刚刚失败时生效,以及它覆盖所有应用还是一份选定的清单。

然后列出你的客户端实际能执行的切换。用户主动断开、退出应用、与服务器失联,在多数客户端里是三条不同的代码路径,它们并不共享同一套拦截策略。有些会在应用退出时解除拦截。另一些则把过滤规则留在原地,直到有东西把它们移除。不要凭假设,去读你所运行版本的厂商设置参考,然后写下你测的是三者中的哪一个。

配置文件也要记录:协议、地址族,以及是否启用了拆分隧道。如果配置文件刻意排除了少数应用,那么整机生效的说法就毫无意义,而你自己配置的排除并不是泄漏。 OpenVPN Connect 的设置参考 就属于那种会说明哪个开关改变哪种行为的页面,尽管各客户端的标签并不相同。

挑选一个在没有隧道时也能工作的诱饵目标

诱饵需要两个属性,漏掉任何一个都会让结果无法解读。在隧道断开且拦截关闭时,它必须能被直接访问,否则它不再应答可能只意味着主机没了。它还不能需要登录、Cookie 或付款,这样一次泄漏的代价只是一行日志,而不是一个会话。

放在你自己控制的主机上的静态页面是最干净的选择。跑着普通 HTTP 服务器的备用虚拟机几乎一样好,公共连通性检查页面也可以用,前提是你接受它的可用性不在你掌控之中。记下地址、端口、地址族,以及请求是否需要名称解析,因为这些每一项都会成为你之后可能必须隔离的变量。

在动开关之前先建立基线。隧道通着时,诱饵必须经由隧道应答,这证明策略路由有效。隧道断开且拦截关闭时,它必须直接应答,这证明目标还活着。只有到那时,拦截状态下的失败才能告诉你点什么。

按固定顺序执行切换

一次只做一个切换,并给每个切换几秒钟稳定下来,因为客户端常常在这段间隙里拆掉并重建规则。每次都跑同样的短检查,观察结果才具备可比性:

curl -sS -o /dev/null -w 'http=%{http_code}\n' --max-time 5 http://decoy.example/
echo "curl_exit=$?"
dig +short decoy.example
curl -6 -sS -o /dev/null -w 'v6_http=%{http_code}\n' --max-time 5 http://decoy.example/
echo "curl_v6_exit=$?"
TransitionExpected with the block onFailure signature
Manual disconnectDecoy stops answering within secondsDecoy still returns 200
Server or path failureBlocked, with no exemption for the old endpointDirect access during the gap
Quit the appClient-dependent; record what happensBlock disappears with the process
Wi-Fi to EthernetBlock holds until the tunnel returnsTraffic flows mid-change

即便日常从不关闭客户端,退出应用这一行也值得单独跑一次。如果拦截在退出时解除,那么崩溃或强制更新会给你同样的暴露,而这是关于部署的事实,不是关于你耐心的事实。在 Windows 上,等效的探针是 Resolve-DnsName decoy.example 和 curl.exe -s -o NUL -w "%{http_code}" http://decoy.example/。

把拦截与解析器故障区分开

页面加载失败有多种原因,其中只有一种是开关在起作用。如果名字解析不了,你学到的是 DNS 被拦截或坏了,而不是数据路径被拦截。再用一个字面地址探测一次,这样答案就完全不依赖解析。

curl 的退出码把这些情况区分开。6 是名称解析失败,7 表示连接被拒绝,28 是超时。被拦截的路由通常表现为针对字面地址的超时或拒绝,而只拦 DNS 会留下 6 并把其他情况都藏起来。缓存页面或强制门户会骗过眼睛,所以证据是退出码,而不是屏幕。

用字面地址在 IPv6 上重复探测。覆盖 IPv4 却忽略 IPv6 的拦截并不少见,值得在你的笔记里单列一行;而在隧道外禁用 IPv6 的客户端应当在两个地址族上都干净地失败。

记录结果所覆盖的范围

隧道恢复后要确认:诱饵经由隧道应答,解析器返回答案,策略还在你放置的位置。然后撤销实验。留在原地的临时防火墙规则、调试路由或测试配置文件会干扰下一次运行,还可能比应用活得更久。

一次运行只覆盖一个客户端版本、一个配置文件、一种切换和一个地址族。把这四项连同结果一起写下来:

  • 客户端版本与平台,以及该设置是按配置文件还是全局。
  • 配置文件、协议,以及任何拆分隧道排除项。
  • 所测试的切换,以及你如何触发它。
  • 地址族与 DNS,以及拦截与未拦截状态下的 curl 退出码。

任何一行留空,测试就没有完成。漫游意味着要重复网络变更那一行。无人值守的重启意味着 检查规则是否会回来,这问的是恢复顺序,而不是开关本身。客户端更新后要重跑整个序列,因为开关很少改变,而它们背后的行为却会变。把诱饵留着:没有什么需要轮换,下一次检查只要五分钟。

相关文章