如何在不使用真实账户的情况下测试 VPN 断网开关
用诱饵页面和备用配置文件运行断网开关测试:覆盖每种中断类型,读取 curl 退出码,并区分真正的封锁与 DNS 故障。
要弄清断网开关是否守得住,你并不需要真实账户,被测试置于风险之中的恰恰就是账户。检查会制造一个短暂窗口,在此期间流量可能流出隧道,也可能不流出,所以载荷应当是可以舍弃的东西。我现在用一个诱饵页面和一个备用浏览器配置文件来做这件事,得到的答案比过去那套浏览器加网页邮件的做法更清楚。下面按照客户端呈现的顺序展开:设置、目标、切换,然后是证据。
这个测试只回答一个狭窄的问题:在这次切换期间,这个应用能否到达隧道之外的网络? 它并不说明其余策略是否合理。把范围保持得这么小,结果才值得写下来。
在客户端里找到开关及其作用范围
在改变任何网络状态之前,先打开客户端找到拦截设置。各家厂商的叫法不同:断网开关、锁定模式、网络锁、拦截隧道外的流量。标签能告诉你的,比它里面的选项少。关键在于拦截是始终生效,还是只在应用判定隧道刚刚失败时生效,以及它覆盖所有应用还是一份选定的清单。
然后列出你的客户端实际能执行的切换。用户主动断开、退出应用、与服务器失联,在多数客户端里是三条不同的代码路径,它们并不共享同一套拦截策略。有些会在应用退出时解除拦截。另一些则把过滤规则留在原地,直到有东西把它们移除。不要凭假设,去读你所运行版本的厂商设置参考,然后写下你测的是三者中的哪一个。
配置文件也要记录:协议、地址族,以及是否启用了拆分隧道。如果配置文件刻意排除了少数应用,那么整机生效的说法就毫无意义,而你自己配置的排除并不是泄漏。 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=$?"
| Transition | Expected with the block on | Failure signature |
|---|---|---|
| Manual disconnect | Decoy stops answering within seconds | Decoy still returns 200 |
| Server or path failure | Blocked, with no exemption for the old endpoint | Direct access during the gap |
| Quit the app | Client-dependent; record what happens | Block disappears with the process |
| Wi-Fi to Ethernet | Block holds until the tunnel returns | Traffic 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 退出码。
任何一行留空,测试就没有完成。漫游意味着要重复网络变更那一行。无人值守的重启意味着 检查规则是否会回来,这问的是恢复顺序,而不是开关本身。客户端更新后要重跑整个序列,因为开关很少改变,而它们背后的行为却会变。把诱饵留着:没有什么需要轮换,下一次检查只要五分钟。