Android VPN 配置文件:先找到所有者,再动手修改
系统 VPN 列表隐藏了拥有端点、路由和密钥的应用。先确认所有者,再对比请求、接收与应用三种状态。
Android 的 VPN 界面只有一行:名称、钥匙图标,也许还有一个“始终开启”开关。它很少显示端点、路由策略、DNS 服务器,也很少显示让连接真正生效的凭据,因为对基于应用的隧道来说,这些都归应用所有。实用结论不是哲学问题,而是运维手册问题:在修改下载来的文件、或者四处寻找集中式配置文件存储之前,先弄清这项设置究竟归哪个组件所有。
先判断连接类型
同一个设置界面上至少存在三种安排。应用可以用 VpnService 建立虚拟接口,自行掌管协议与私有配置,也包括没有远程出口的本地过滤应用。Android 还能通过 Ikev2VpnProfile 提供平台级 IKEv2 配置,该接口从 API 30 起可用,此时配置文件更多由平台掌管。此外,服务商应用也可能自带服务器列表,并在内部拼装设置。
adb shell dumpsys connectivity | grep -i -A12 "VPN"
adb shell cmd connectivity list-owners 2>/dev/null || true
第一条命令显示当前活动的 VPN 网络及其链路属性,也就是实际应用的状态。如果那一行写着你能认出的包名,就从该应用自己的配置界面入手,而不是系统界面。
记录所有者与配置范围
动手之前先记下四件事:所属包名;连接位于个人资料还是工作资料;应用显示的配置或连接名称;以及由谁管理。设备所有者可以配置个人资料用户无法编辑的工作资料 VPN,而同一个应用装两次,就等于有了两个彼此独立的所有者。
这一步能挡住最常见的一小时浪费:改了一份并不是当前已连接的配置。应用往往保存多份配置,而“当前生效”是应用自身的属性,不是 Android 那一行的属性。
对比请求、接收与应用三种状态
这是三个不同阶段,三者之间的差异会告诉你该修哪个组件。
| Stage | Where to look | What it proves |
|---|---|---|
| Requested | The app's profile editor or imported file | What the owner intends to use |
| Received | Sanitized app log of server-supplied options | What the peer actually pushed |
| Applied | Link properties and routes after connect | What the device is really using |
“应用”阶段是唯一无需相信任何一方日志就能观察到的状态。把活动链路属性里的 DNS 服务器与路由,同配置所声称的内容逐项对比;如果两者不同,要么服务器推送了别的东西,要么应用套用了你没预料到的策略。
adb shell ip addr show tun0
adb shell ip route show table all | head -40
接口名称因应用而异,所以先列出接口,再读取隧道建立时新出现的那一个。只存在于应用编辑器、却不在这里的路由,说明它从未被应用;只出现在这里、却不在编辑器中的路由,则来自别处。
修改所有者真正读取的那份文件
对于导入的 OpenVPN 配置,应用通常会另存一份副本。事后修改最初下载的文件不会改变下一次连接;请使用应用文档中说明的编辑器,或者重新导入并确认当前生效的是哪一份。改文件与改配置,区别就在这里。
服务商应用常常从服务器列表拼装设置,而不写用户可编辑的文件。没有导出按钮,并不能证明 VPN 是假的;导出的文件也可能缺少另一台设备所需的设备绑定密钥或注册材料。请把导出与导入当作两件各有前提的独立操作。
写支持记录,但不要泄露机密
有用的记录会写明具体的应用与配置、看起来不对的设置,以及每个阶段的证据。例如:这份配置从服务器拿到私有 DNS 地址,但目标工作应用无法解析其服务,已应用的链路属性显示的是那个解析器,而配置编辑器显示的却是另一个。
机密不要写进记录。为了确认所有者,并不需要 root 设备去翻应用私有存储;猜出来的数据目录路径也不是受支持的接口。如果答案需要只有应用才能看到的字节,就请所有者导出诊断信息,而不要自己临时拼凑。
事情做完后要闭环:确认当前配置名称,重读已应用状态,并断开一次,验证改动在重新连接后依然存在。只存在于编辑器里的设置,等于还没有生效。