基于路由的 IPsec 如何配合 XFRM 接口工作
XFRM 接口为基于路由的 IPsec 提供可路由通过的设备。if_id、其背后的安全关联以及外部路由都必须对齐。
基于路由的 IPsec 把过去由策略选择器做出的决定交给路由表。在 Linux 上,实现这一点的部件是 XFRM 接口:一个虚拟设备,其流量按接口标识符而非选择器与 IPsec 状态匹配。创建一个只需一条命令,也完全不能证明隧道是否存在。该设备是路由与安全策略之间的挂钩,在有任何东西受到保护之前,挂钩的两侧都必须配置好。
这个设备是什么,不是什么
XFRM 接口是一个路由句柄。被路由进它的数据包会与引用同一接口标识符的 XFRM 策略匹配,若策略和状态都存在,就会被封装。缺少这些,接口依然存在,计数器不动,流量去不了有用的地方。
这是第一个诊断分界。 进入该设备的路由是路由事实,已安装的状态是安全事实,而设备上增长的计数器两者都不是。当人们说因为接口显示 UP 所以隧道已建立时,他们描述的是一个没有自身对端的虚拟设备的链路标志。该标志只表示设备已被创建并启用,仅此而已。
还有一条边界:接口标识符不是名字。两个名称相似但标识符不同的设备并不共享状态,而用错误标识符配置的连接会安装一条任何路由都不会使用的状态。
按正确顺序构建一个
从外部设备和一个你也会写进守护进程配置的数字开始。示例使用 eth0 作为外部接口、42 作为标识符,这些地址应替换为你自己的。
把设备启用起来,然后在改动 VPN 配置之前确认内核记录的标识符:
sudo ip link add xfrm0 type xfrm dev eth0 if_id 42
sudo ip link set xfrm0 up
ip -d link show xfrm0 | grep -o 'if_id [0-9]*'现在在 strongSwan 中用同一标识符配置连接,因为守护进程必须安装引用它的策略和状态。把本地和远端流量选择器设为你打算路由的网段,然后把这个网段路由进该设备。守护进程配置和路由表必须在标识符和目的地上都一致,二者谁也不提供对方。
让 IKE 和 ESP 远离隧道路由
指向 XFRM 设备的默认路由会连封装后的数据包及其承载的流量一起捕获。结果就是环路:网关试图让自身的 ESP 走 ESP 本应建立的那条隧道。
解决办法是 为对端外部地址指定更具体的路由并让它走物理接口,因为它匹配更多比特,从而胜过默认路由。多条隧道共用一张表时,基于标记的路由做同样的工作,strongSwan 为基于路由的部署记录了这两种做法。
无论选哪种做法,都要确认外部数据包未被封装就发出。快速检查是隧道起来后 ping 对端的外部地址;若接口在线时这一步失败,应怀疑包被捕获而不是不可达。同样的道理适用于 IKE 端口,因为守护进程自己的 UDP 流量不能路由进它正试图建立的设备。
在怪罪加密之前,先在两处检查计数器
接口计数器和状态计数器衡量的是不同阶段。被路由进设备的数据包即使没有匹配的状态也会让设备计数增加,而状态计数器只为真正被封装的流量变化。
两个都读,然后读守护进程对子关联的看法:
ip -s link show xfrm0
sudo ip xfrm state list | grep -E 'src|proto|mode'
sudo swanctl --list-sas状态输出为空而设备计数器在涨,说明路由正常但策略不匹配,通常是标识符或选择器出错。远端毫无报告而状态计数器在涨,说明数据包发出却没到达或认证失败,这指向路径或对端配置。列出的子关联流量为零,是一端的选择器问题,而不是加密算法坏了。
决定由谁安装路由
一张路由表有两个所有者,是路由抖动的常见来源。如果守护进程自动安装路由,你的网络管理器就不要再通过同一设备安装默认路由;启动脚本手动添加的路由会在守护进程下次重配时被删掉。
选一个所有者并写下来。当守护进程拥有路由时,把启动脚本挡在表外,让连接定义描述流量选择器。当网络管理器拥有路由时,关掉自动安装,并接受守护进程在重连时不会修复缺失的路由。
转发和防火墙规则是其上的另一个决定,因为为其他主机转发流量的网关两者都需要。基于路由的 IPsec 让这类流量可以用普通路由工具轻松表达;它并不会让策略层变成可选项。