绿色的 VPN 图标是对某件事的断言,而有用的问题是:它断言的是什么。在手机上,它可能反映某个客户端的隧道、当前网络的传输方式,或一次成功访问内部页面的请求。这些观测来自不同的来源,以不同的频率刷新,并且可能在同一块屏幕上互相矛盾。正因为如此,图标看起来一切正常时,你面前的浏览器却可能打不开网页。

先划定范围,再去看颜色;否则颜色回答的将是一个没人提出的问题。

图标回答的问题,比你以为的要窄

从一个明确的范围开始,例如使用已批准个人隧道的个人浏览器。工作配置文件的隧道并不能回答个人应用的问题,而按应用配置的 VPN 可能恰好排除了你正在测试的那个浏览器。本地过滤客户端可能显示已连接,却什么也没有发给远程网关,因为它的隧道在设备上就终止了。

在 Android 上,指示图标背后的网络回调报告的是某个网络的传输方式与能力。VPN 传输说明的是哪张网络承载流量,而不是哪些应用或地址族在使用它。

用证据建立状态表

三种或四种状态就够了,前提是每种状态都点明它背后的证据。下表的列从可观测的事实出发,而不是从你想显示的颜色出发,这样才能避免把过期读数当成成功。

Signal actually observedWhat it establishesWhat remains open
Target client reports an established tunnelThat client believes its tunnel is up, within its own scopeOther apps, other profiles, other address families
Active network exposes a VPN transportSome tunnel carries the current networkWhich app it belongs to and where it exits
Probe to a private host returned fresh dataOne request reached one destination at one timeEverything the probe does not touch
Callbacks stopped or data is older than the refresh windowNothing current is knownAny statement about the tunnel state

实际中最常被丢掉的正是最后一行。当数据源死掉时仍保留最后一个值的指示灯,等于把历史当成现在报告,而用户会把它读成实时状态。把这种情况标为过期或未知,并选择不含隧道意味的措辞。然后让标签在数据源停止的那一刻就改变。

查清设备实际报告了什么

实体指示灯或小组件应当由受支持的观测驱动,而不是由对最后一次已知正常状态的猜测驱动。下面这些 Android 命令无需安装任何东西,就能显示传输方式与平台的常连配置。

adb shell dumpsys connectivity | grep -i -A4 vpn
adb shell settings get secure always_on_vpn_app
adb shell settings get secure always_on_vpn_lockdown
adb shell dumpsys netstats | head -40

常连相关的键值说明平台是否被配置为保持隧道、并在没有隧道时拦截流量;它们并不说明隧道此刻是否健康。在把任何东西显示为已连接之前,先用一次新的探测去对照那份配置读数。

如果观测无法继续,显示界面必须能够说出这一点。一盏接在已经不再运行的自动化上的灯,比没有灯更糟,因为它在断言一个没人测量的状态。

把警告与强制执行分开

能察觉断线的自动化是在事件之后才触发的,所以它不能充当那道阻止数据包在空档期泄漏的边界。如果必须禁止直接回退,就配置平台的拦截策略,并故意关掉隧道来验证它。指示灯负责报告,策略负责执行。

为强制合规而关闭网络接口的警告任务,也可能把设备锁在它所需要的重连之外,形成一个隧道再也回不来、警告再也清不掉的循环。

先决定观测者不确定时界面应当显示什么,然后停掉观测者来测试这种情况。如果答案仍然是已连接,那说明指示灯在测量过去。

相关文章