它在你的 Mac 上能用,于是看起来像是可以交给用户的东西。这个假设是首先要丢掉的。Apple 的 TN3165 明确指出,Packet Filter 不是面向广泛分发产品的受支持 API,并把有特权、受管控的站点管理视为合理场景。因此,基于 PF 的 VPN 锁定是有负责人的本地运维策略,而不是能打包进应用的功能。

PF 不是打包面

这一区别并非纸上谈兵。依赖 PF 的分发产品会继承 Apple 对它的每一次改动、与同样写入规则的其他工具的每一次冲突,而且没有任何“这套安排会持续可用”的支持承诺。自行管理机器的站点则是另一种关系:它可以记录依赖、针对每个操作系统版本进行测试,并接受维护工作。

有些安装建议越过了值得点明的界线。为了让一个 anchor 加载而覆盖整个系统规则集、修改 Apple 的系统启动配置,或关闭系统完整性保护,都不是可复用配方可以接受的要求。如果某份公开指南需要其中任何一项,那它描述的是实验室,而不是可部署的策略。

先写出流量意图,再写语法

在挑选任何一个关键字之前,先决定允许什么。通常需要三条路径:VPN 客户端自身到其服务器的传输、隧道内受保护的应用流量,以及确实需要直连的设置或本地服务。

为每个拟议的例外指定目的地、传输方式和负责人。允许到某个端点的所有端口,放行的范围远超隧道所用的那一种传输,而多出来的暴露是在无人决定应当如此的情况下出现的。允许公共解析器是同一陷阱的友善版本:即使在隧道断开时它也会建立一条直连 DNS 路径,因此名称查询仍会泄漏。

PathDestinationOwner
VPN transportGateway address, one UDP portNetwork team
Tunnel trafficInternal prefixesApplication owner
Resolver exceptionNamed internal resolverSecurity team

对例外真正有用的检验是:你能否说出提出它的人,以及它防止的故障。如果两个答案都不存在,这条规则多半是在绕过一处配置错误,而那个错误本该保持可见。

utun 编号不是身份

MacOS 把隧道接口创建为 utun 设备,而分配给你 VPN 的编号在重启、重连或存在另一个客户端时 并不稳定。列出一串猜测编号的规则不是策略,只是一个下午的快照。

把规则锚定在能识别预期提供方的东西上:隧道分配的地址规划、拥有该接口的进程,或 VPN 客户端自己维护的配置。然后记录这种识别是如何运作的,因为一年后复核这条规则的人不会拥有你的 shell 历史。

让已加载的策略可归因

anchor 名称只是组织规则;它并不能证明生效策略就是你想要的那套。anchor 之间的优先级、其他软件加载的规则以及既有状态,都可能改变结果。与同一台机器上其他所有负责 PF 的人一起复核生效集合,并把归属记录在配置所在的同一处。两个负责人以不同假设编辑不同的 anchor,正是锁定出现漏洞的常见方式。

把规则集放在站点受支持的配置路径中,对其进行版本管理,并注明测试过哪些 macOS 版本。靠手工应用、只由一个人记住的改动,无论文件头怎么写,都不是受维护的基础设施。

测试转换,而不是已连接状态

隧道正常时截的图几乎证明不了什么。应当逐个走查状态:任何连接之前的启动、正常工作的隧道、无预警断开的隧道、主动断开,以及从 Wi-Fi 切换到热点。每个状态都有自己的答案,真正有意思的是失败,而不是顺利路径。

在每个状态下,记录哪些目标是刻意可达的。分别检查 IPv4 和 IPv6,测试名称解析,并纳入一条在转换前就已建立的流,因为既有连接并不总是遵循新策略。隧道断开时浏览器失败只是一个数据点,并不能证明其他所有路径都被封锁。

最后,保留一种不依赖你正在改动的网络路径的恢复方式。本地存储中一份已知良好的配置,加上有文档记载的加载方式,才能把锁定变成策略;没有它们,一次糟糕的修订就会把管理员锁在那台本该受保护的机器之外。

相关文章