状态输出里看不到 CHILD SA,隧道看起来像是死了,然后发往远端子网的一个 ping 就把它拉了起来。在按需 IPsec 配置里,这个顺序就是设计,而不是故障。trap 策略会安装一个选择符并等待,而第一个与之匹配的数据包才会启动 IKE 和 CHILD SA 协商。

部分困惑来自用词:“up”被用于两种不同的状态。 配置已加载,内核策略也存在,但数据关联并不存在。只统计活动 SA 的监控会把健康的站点报告为宕机,只要没人向它发送流量。

空闲的按需隧道没有可供显示的 CHILD SA

trap 条目本身并不认证任何东西。它请求内核为选定的流量保留一条策略,并在某个数据包需要该策略时触发 acquisition。守护进程收到 acquisition,将其与 child 定义匹配,并从那里开始协商。在此之前也没有 IKE SA 可显示,所以两个列表可能同时为空。

正是这个顺序让日志变得可读。先出现 acquisition,然后是 IKE_SA_INIT 和 IKE_AUTH,最后是 CHILD SA。如果日志在 acquisition 之后立刻结束,说明触发器生效了。协商失败了,下一个问题就关于凭据、提议或可达性,而不是 trap。

使用 Linux 内核后端,你可以在任何 SA 存在之前看到策略。运行 ip xfrm policy,寻找方向为 out、模板指向该连接的选择符。这条记录就是按需状态,它的存在是首先要确认的事情。

start_action 决定到底有没有东西在等待

在 swanctl.conf 里,每个 child 都带有一个 start_action. start 在配置加载时启动,trap 安装策略并等待,而 none 把启动交给别的机制。只有 trap 才会产生上面描述的“ping 一下就上来”的行为。

children {
    office-lan {
        local_ts = 192.168.50.0/24
        remote_ts = 192.168.70.0/24
        start_action = trap
    }
}

两个流量选择符定义了什么算作有趣的流量。来自这些前缀之外主机的数据包不会触发 trap,而会照常路由。为了让触发器更积极而放宽选择符,也会扩大隧道声称保护的范围,所以应当从你真正想加密的流量中推导它们。

swanctl.conf 参考文档 列出了可接受的值,以及单独的 close 和 DPD 操作,它们规定 SA 存在之后会发生什么。

弄清触发器到底有没有触发

先用 swanctl --list-conns 确认 child 已按预期动作加载。然后从 local_ts 内的主机向 remote_ts 内的地址发送一个数据包,并观察 swanctl --list-sas。如果输出没有变化,就没有 acquisition 到达守护进程。

静默 trap 的两个常见原因:数据包在命中策略之前被做了源 NAT,因而不再匹配 local_ts;或者连接因语法或凭据错误而从未加载。先重新运行 swanctl --load-all 并读取输出,再去动选择符。加载失败的连接不会安装任何策略,所以流量没有可触发的东西。

方向也很重要:为出站流量安装的 trap 不会在入站数据包上启动。如果应由远端把隧道拉起来,它需要自己的 trap,或者这一侧需要 start.

等待第一个数据包并不总是正确的取舍

交互式会话会感受到建立成本。第一个请求要付出 IKE 交换和 CHILD 协商的代价,截止时间很短的客户端可能在 SA 建立之前就放弃。主动的 start 能消除这第一个数据包的延迟,但会为可能永远不会到来的流量保持隧道。

三个事实决定选择:路径使用的频率、第一个请求的截止时间是否紧张、对端在启动时是否可达。偶发的批量流量和启动时可能离线的对端都倾向于 trap。对延迟敏感的客户端和始终可达的对端则倾向于 start。如果两侧都能发起,就要约定由谁持有触发器,以免出现重复协商。

已安装的策略也不是防泄漏的保证。如果要求是 fail-closed,防火墙必须丢弃没有 SA 的流量,而那条规则活在 child 定义之外。

记下下次争论时能终结它的三行

写下选择符、启动动作,以及显示策略存在但没有 SA 的命令输出。这三行能在下次有人报告隧道宕机时,把“按需且空闲”和“没有加载”区分开。记录它们只要一分钟。没有它们,同样的排查会从零开始。

要从真正位于选择符内部的主机测试。从路由器本身发出的 ping 往往走另一条路径,无法证明保护其后方子网的策略。

相关文章