XFRM 默认路由吞掉了 IKE 和 ESP:保住外层路径
保护一切的路由策略也可能捕获维持隧道的报文。标记 IKE 和 ESP,或者保留一条对端路由。
流量受到保护,隧道建立起来了,然后它在下次密钥更新时死掉。一条经过 XFRM 接口的默认路由描述了你想要保护的流量。它同时也吞掉了维持保护所需的报文。
涉及的两个目的地址不可互换。路由必须明确说明这一点。
对端查找究竟去了哪里
记录活动规则、保存 XFRM 路由的表以及对端的公网地址。然后按真实源地址和标记查看外层连接会走哪条路径。泛泛的目的地址无法说明这条控制路径。只有真实的源和标记才能给出有用的答案。
初次连接成功也证明不了什么。故障往往出现在某次路由安装改变了答案之后。启动成功,第一次续期就不行了。
ip rule show
ip route show table 220
ip -4 route get 198.51.100.44 from 10.40.0.2
ip xfrm policy list
如果对端的查找落进了 XFRM 接口,外层报文就被路由进了它们自己构建的隧道。这就是环路,一条命令即可看见。
现代网关上的排除方案
strongSwan 的 基于路由的 VPN 文档 给出了两种可行做法。一种标记 IKE 和 ESP,使指向 XFRM 表的规则匹配不到它们。另一种保留一条对端路由或排除项,让查找仍然能够到达。
选择你的规则集能够无副作用表达的那一种。当栈的其余部分已经在用标记时,标记是干净的。当同一个掩码在另一条规则里表示别的含义时,它就是隐患。无论如何,两种报文都需要这种处理。
只标记 IKE 会让数据报文留在被捕获的路径上。这样得到的隧道能完成握手,却什么也承载不了。
标记是报文 fwmark 中一个网关上没有其他东西占用的位:0x1 配掩码 0x1 是常见选择,而且必须在两处设置,排除才能生效。Charon 需要在 IKE 套接字上设置它,子连接入站和出站的标记设置也需要同一个值,这样封装后的报文也会带着标记发出。用 0x1 而不是 0xffffffff 作掩码,可以让其余位保持空闲;当同一主机上另一个子系统已经在标记报文时,这一点很重要。两处都设置好之后,规则写成排除形式,于是被标记的报文跳过保存 XFRM 路由的表,落到主表:
ip rule add not fwmark 0x1/0x1 lookup 220 pref 1000
ip -4 route get 198.51.100.44 from 10.40.0.2 mark 0x1
然后带上标记读取答案。没有标记,你检查的是受保护流量所走的路径,恰好与本节的提问相反。
自动安装对构建做了哪些假设
XFRM 接口的自动路由安装 取决于 strongSwan 版本及其配置。接口 ID、已安装的策略和关联都必须指向预期的对象。不一致会表现为一条悄悄指向真实位置的路由。
从另一台网关复制表号或标记掩码,正是冲突的开始。先检查已有谁在用它。冲突影响的流量远远超出你想改的那条隧道,而症状很少指向那次复制。
对端地址变化应当纳入设计。为昨天的地址写一条主机路由不是端点恢复方案,而标记能经受住这种变化。
观察第一次续期
在受保护路由安装之后检查外层路径,而不是之前。然后观察下一次续期和一次应用交互。故障通常出现在这个转换点,而不是启动时。
ip -4 route get 198.51.100.44
sudo swanctl --list-sas
sudo tcpdump -ni any 'udp port 500 or esp'
临时移除受保护的默认路由通常能恢复连通性。这只是诊断结果,不是最终方案。
目标是让内层流量与承载它的外层报文稳定分离。把选定的机制及其表号或标记写进网关笔记。否则下一个改动规则的人会重新引入环路。