读到一行写着 Security Associations (1 up, 0 connecting) 的状态,看起来像在报告一条正常工作的隧道。有两个子网同时从它经过,所以这个数字看起来在撒谎。它没有撒谎;它数的是 IKE 关联,而其中一条可以承载多个子项。在改动提案或路由之前,先把清单读一遍。

为什么标题和流量对不上

旧的 stroke 输出把总数称为安全关联,并且从 IKE 关联管理器取这个数。每条已建立的 IKE 关联都贡献一条,无论下面挂了多少个 CHILD SA。一个 IKEv2 父项通常承载多个子项,每个流量选择器对对应一个,而子项协商出的选择器可以覆盖不止一个地址或前缀。因此你配置里的地址数量,与标题里的数字并没有固定关系。

现代输出有时显示总数,而不是旧的 “up” 说法,而由 swanctl 管理的守护进程完全不受旧 stroke 设置驱动。不要假定措辞,也不要假定跨版本的计数规则。

动手之前先比对三份清单

先看已加载的内容,再看已协商的内容,最后看真正在传包的内容。这是三个不同的问题,每个都有自己的命令。

swanctl --list-conns
swanctl --list-sas

第一条列出守护进程已接受的连接定义。第二条列出已建立的 IKE 关联及其子项,真正的层级就出现在那里。定义在文件里却不在第一份清单里,说明它从未被加载,发起方重试多少次都没用。如果你改用旧接口,对应的组合是 ipsec statusall 和同一份 swanctl 清单,取决于配置归哪个插件所有。不要在同一台主机上混用两个守护进程的工具,也不要指望得到一个一致的答案。

swanctl --list-sas --raw | head -40
ip -s xfrm state

原始格式让标识符和选择器保持可见以便比对,内核状态清单则显示协议栈认为自己装了什么。当守护进程和内核不一致时,要么守护进程在已有子项周围重启过,要么内核对象被从下面删掉了。

读层级,不要读总数

一个示意性的已建立父项带两个子项,看起来就是一个节点下面挂着两个子项,各自带有自己的状态和模式。把真实输出导出来自己数子项,而不是读别人从看板上贴来的摘要。

swanctl --list-sas
swanctl --list-conns --raw | grep -A4 'accounting'

一个父项带两个已安装子项,就是一条健康的两子网隧道。一个父项带一个已安装子项和一个缺失子项,是另一种情况,缺失子项的选择器才是要和对端提案比对的东西。在密钥更新期间,旧子项和它的替代者可能短暂同时出现。把时间戳和快照一起留下,因为更新中途取的计数看起来像重复,而之后取的计数看起来像丢失。

已加载、已安装和正在通过的流量

处于已安装状态的子项有协商好的参数和一条内核表项。但它不一定真的传过包:选择器可能比你预期的流量更窄,路由也可能在隧道看到它之前就把流量送去了别处。从授权主机发送一个符合已协商选择器的流,然后去读子项的计数器,而不是读标题。在你产生匹配流量时计数仍停在零,指向的是路由或策略,而不是 IKE。

swanctl --initiate --child accounting
swanctl --list-sas --raw | grep -E 'bytes|packets'

启动一个具名子项是有明确结果的主动操作,它把“没人请求所以连接空闲”和“连接起不来”区分开。按需的陷阱策略表现得和第一种情况完全一样,所以在把它当成故障之前,先读连接的开机设置。

当计数真的出错时

如果已加载的清单里缺少某个定义,先看配置加载过程,以及正在运行的是哪个守护进程实例。如果它已加载却从不协商,就把提案、认证上下文和选择器与对端逐项比对,一次一个子项。每次只改一个元素,并记录你改的标识符。知道是哪一条时,回滚提案很容易;在三次没有分开的改动之后,那就只能靠猜。

先纠正误读。大多数关于第二条隧道“消失”的报告,最后都收在一个父项下装着两个子项上,而唯一出过问题的,是人们宁愿相信摘要行也不看层级。

相关文章