设备上的 VPN 标记与出口地址:各自能证明什么
在设备上读取的网络标记与服务器观察到的地址是两类不同的证据。先决定你的问题需要哪一类。
手机应用和远端服务器从不同的事实出发,谁也无法借用对方的事实。应用可以向操作系统询问自己所使用的网络,而服务器只知道连接上到达了什么。运行自己的出口会改写后者,前者则原封不动。究竟哪一个能回答你的问题,取决于问题本身。
两个观察点,两类证据
本地证据描述设备。它包括承载流量的接口、平台报告的传输方式,以及调用方应用被允许查询的内容。远端证据描述连接:源地址、协议、时序,以及应用选择发送的任何内容。没有任何一个观察点是另一个的超集。
把两者混在一起,会得到听起来精确却无法核实的说法。标记证明的是设备上某个网络对象的情况,而不是远端服务如何归类这个请求。
在争论检测之前,先写下问题针对哪一个观察点。问题究竟是某个应用能否知道隧道处于活动状态,还是某项服务能否推断请求来自哪里?这是两项彼此独立的调查,回答其中一个并不能说明另一个。
本地平台接口能报告什么
Android 提供了一个具体的标记。NetworkCapabilities 对象可以报告 TRANSPORT_VPN,而 hasTransport 用来检验该对象上是否存在这种传输方式。应用从连接服务取得该对象并读取它,前提是拥有网络状态权限。
结果是本地平台信息,而不是去查询服务商的地址段。它描述的是调用方应用正在使用的网络。
有两点限制值得注意。排除某个应用的分流隧道规则,可能让同一部手机上的答案与同事看到的不同,因为该应用可能被绑定到别处。标记之所以存在,是因为操作系统对 VPN 接口做了建模,而不是因为某个特定应用在采集它。应用是否读取该字段、是否转发、是否忽略,都是该应用自身的属性。它的清单文件和文档才是这个问题唯一可靠的来源。
adb shell dumpsys connectivity | grep -i -m5 vpn
远端服务能看到什么
服务器能看到连接的源地址、传输方式和时序,还可以用注册信息或路由数据来补充地址。它也能收到应用发送的一切,包括应用请求且用户同意时的位置。这些通道彼此独立,只有一项像地址查询。
注册在主机商名下的地址暗示隧道,而注册在住宅网络下的地址暗示家庭宽带。两者都只是统计线索,不是关于设备的事实。
住宅地址并不能把某人定位在该地址,主机地址也不会点明运营方或国家。把推断当成确定的服务,有时会出错却无法察觉。如果要求的是可靠性而不是经验法则,地址数据给不了,而承认这一点的设计比掩盖猜测的设计更诚实。
| 证据 | 它回答什么 | 它无法显示什么 |
|---|---|---|
| 本地传输标记 | 该网络对象是否为 VPN | 谁在运营出口,或设备身处何地 |
| 远端源地址 | 哪个地址到达了服务 | 设备是否同时携带隧道 |
| 应用负载 | 应用选择发送了什么 | 应用没有发送的一切 |
自建出口为何只改变一侧
运行自己的出口会改变远端服务看到的源地址,这可能把它移出该服务与商业服务商关联的地址段。本地网络模型没有任何变化,因为隧道仍然是隧道,操作系统依然会报告它。
证据的一侧在动,另一侧不动。两者之间的落差正是预期破裂之处。
浏览器是第三种情况,有自己的接口和限制。网页内容无法读取原生的能力对象,把移动操作系统的特性当作网页可用的东西是范畴错误。如果问题涉及网站,就去研究网站实际能获得什么,而不是照搬平台 API。
用你提出的问题来决定
如果问题是某个应用能否观察隧道状态,那么平台接口才是该看的地方,答案就在该应用的代码与权限里。如果问题是服务能推断什么,连接元数据就是证据。法律或合同问题,两者都无法了断。
在收集任何东西之前,先用一句话把问题命名。那句话决定了哪个观察点重要,也能防止调查滑向另一场争论。
报告时给每项观察标上来源,因为没有标注的说法无法复核。本地标记与地址推断都有用,也都不是决定性的,所以把它们合并成一个结论是错误的。
当服务拒绝已授权的连接时,走它支持的复核渠道,而不是改动本地设置去掩盖某个信号。移除一项观察,永远不能证明其余观察已经消失。