杀开关已开启,有一个应用被刻意排除在隧道之外,两条要求此刻互相冲突。一条说除了隧道之外什么都不许出去,另一条说这个程序必须直连。每个客户端对这一冲突的处理都不同,而设置页很少说明哪条规则优先。在相信任何标签之前,先把逐应用的策略写下来。

两套策略,一台机器

杀开关是关于故障的承诺:当隧道不再保护流量时,流量就停下。分流是关于选择的承诺:这些程序或目标走隧道,那些不走。第二个承诺制造出第一个承诺必须裁决的流量。两个承诺都没有错,只是不同的人为不同的威胁写下它们。

可能出现三种结果,而只有一种是部署本意。被排除的应用可能在故障期间保持直连,这尊重了分流却破坏了杀开关。它也可能和其他一切一起被封住,这尊重了杀开关却破坏了分流。或者它只是偶尔被封,取决于接口消失之后平台如何评估规则。最后这种才会产生工单。

先写应用清单,再写规则

列出必须走隧道的程序、必须直连的程序,以及绝不能出现在任何清单上的名字或目标。解析器的行为和 IPv6 一侧要单独列出,因为两者都可能遵循与网页流量不同的策略。

逐应用规则通常匹配的是可执行文件或软件包,而不是它内部的配置文件。浏览器配置文件、隐私窗口和扩展本身没有网络身份,因此继承的是进程拿到的那个身份。该浏览器启动的辅助进程,可能根本不继承同一条规则。

需要两份清单,而不是一份:隧道必须承载什么,以及无论何种理由都不能离开隧道的是什么。同时出现在两份清单里的应用属于需求冲突,而不是实现细节,必须在配置客户端之前解决。

故障期间客户端会做什么

有些实现会在故障期间封住被排除的应用,并在重连后恢复其访问。另一些则始终保留直连路径,这与分流一致,但作为安全属性更弱。平台级锁定可以完全覆盖客户端自己的逐应用选择。这个差别不是外观问题,因为它决定了被排除的应用究竟属于策略例外,还是一个漏洞。

Android 的常开 VPN 加上「无 VPN 时阻止连接」选项是最清楚的情形,因为执行锁定的是平台而非客户端,隧道断开时被排除的软件包也会和其他一切一起被封。在自己驱动里应用逐应用排除的桌面客户端,通常会把被排除的进程留在物理网卡上,因为它从一开始就没有接管该进程的流量。两种行为都站得住脚,而只有一种符合「被排除的应用必须保持可用」这一要求。解释结果之前,先问清是哪个组件在执行这条规则。

要读的是你面前这个操作系统的行为,而不是别处同名设置的说明。执行接口并不相同,同一个复选框在桌面和手机上可能意味着严格不同的事。版本也很重要,因为锁定控制在各代 Android 之间换过位置,而客户端侧排除清单并不等于平台级锁定。

三个时刻:隧道通、隧道断、重连后

在三个时刻发出无害请求:隧道正常工作时、你在意的那次故障期间,以及重连之后。单凭一次浏览器结果无法确定被排除应用的行为。

curl -sS --max-time 8 https://api.ipify.org
curl -sS --max-time 8 --interface tun0 https://api.ipify.org
dig +short example.com

出口地址显示走了哪条路径,显式的接口测试则显示当隧道是唯一可用出口时会发生什么。执行任何一条之前,先在每行旁边写下预期结果,否则输出会被事后解释。

如果被排除的应用掉线,先检查策略优先级,再添加宽泛的防火墙放行,因为那种修补会毁掉你正在检验的区分。如果它保持直连,请确认那是文档化的例外,而不是意外的回退。若要求覆盖整台设备,就把例外清单缩短到可以手工验证为止。

相关文章