在受监督的 iPhone 上使用受管理的 Always On 描述文件时,手机会为每个活动的 IP 接口各保持一条隧道,因此蜂窝网络和 Wi-Fi 各自拥有一条。随后服务器会为一个设备列出两条 IKE 安全关联,常常共用一个虚拟地址,而第一反应往往是把它称作 rekey 循环并开始调整计时器。这种反应通常是错的。请按证据在服务器上出现的顺序走完下面的步骤,在服务器告诉你属于哪种情况之前,不要动手机设置。

从服务器已有的两行开始

用 swanctl --list-sas 列出关联,并读取两条记录中的四个字段:远端地址、已认证身份、分配的虚拟 IP 和创建时间。一个身份、一个虚拟 IP 却有两个不同的外部地址,正是引出这个问题的形态,值得在任何改动之前先记下来。接着检查各自挂载的子关联,因为流量选择器决定了目标查找究竟能否区分这两条隧道。几秒内出现又消失的一对,与两条都存活数小时的一对是两回事。

下结论之前先按创建时间排序。输出里的相邻毫无意义,而表格形式的清单恰恰会诱发这个错误。

判断你看到的是哪一种重叠

IKEv2 rekey 与 make-before-break 重新认证会刻意制造短暂重叠:先建立新关联,再删除旧关联。时间戳可以定性,因为新关联出现后一两秒才消失的旧 SA 正是完成本职的续期。独立的接口隧道从不会这样,因为每条都在其接口保持活动期间存在,删除一条并非由创建另一条推导而来。

Apple 的受管理 Always On 行为是按接口的,所以受监督设备看起来比手工配置的描述文件更繁忙是合理的。服务商应用的自动连接开关并不表示同一回事,普通的按需规则也不表示。Apple 部署概览描述了按接口的模型;在假设存在循环之前,先把你的两行与它对照。两种形态都取自同一个服务器地址池,因此重叠是你唯一的早期信号。

看清为什么两条隧道共用一个虚拟地址会破坏回复

发往手机的回复被送往内部地址,而内核按目标和策略选择出站隧道,而不是按手机使用的接口。两条并发关联持有同一虚拟 IP 且策略重合时,路由决策就无法说出某个回复属于哪个会话。部分回复走了错误的隧道,手机便表现为单向可用,或在 Wi-Fi 起来时断掉。两条命令输出可以证明这一状态:swanctl --list-sas 显示两条 SA 上是同一个虚拟 IP,ip xfrm policy 显示两个相同的选择器。

正是这一对输出要贴进变更记录。单看任何一条都不足以说明问题,因为各自都可能看似合理。

这是服务器侧的寻址与策略问题,不是手机行为异常,也没有任何客户端设置能分开两个相同的内部地址。地址池把同一个值发了两次,策略安装器接受了它。在责怪客户端之前,先从服务器一侧读结果。

改地址池或并发模型,而不是改 rekey 计时器

在 swanctl 配置中,唯一性是对连接的显式策略:unique = replace 在新连接建立时移除较旧的连接,unique = keep 则拒绝新来的连接。两个值都在建立连接时起作用,而不是作用于其中的子 SA。

connections {
  ios-alwayson {
    unique = replace
  }
}

对按接口的客户端来说,两个值都不中性。keep 通过拒绝第二条隧道恢复了整洁的状态界面,却破坏了受管理的设计;replace 则拆掉较旧的隧道,是同一妥协的反向版本。如果两条隧道确实都需要,地址池后端必须为同一身份签发不同的租约,其租约键必须能区分请求。静态的身份到地址映射表会很乐意两次返回同一地址,并用更多配置重现原来的问题。在添加第二条静态映射之前,先确认后端如何生成租约键。

测试你真正会遇到的切换

在会话活动时走出 Wi-Fi 范围,再走回来,确认两个方向都能收到回复。做两次,因为第二次切换往往才暴露出过期的策略。用一个在你打开的连接上应答的服务来测试,并在隧道承载流量而不是空闲时重复走出。只能发、收不到的,在握手日志里看着健康,在浏览器里却是坏的。

状态界面缩成一行并不是设计可用的证据,只能证明有一条隧道消失了。切换要通过,两个方向都必须工作。把你观察到的内容,连同重叠检查的两条输出一起记下来,让下一位工程师可以对照,而不必重走一遍。

相关文章