IPsec 配置备忘 Part10 - Xfrm 与 Nftables
Xfrm Interface 与 Route-based VPN
到目前为止,我们所有的配置都是基于 Traffic selector 来选择要加密的流量,而非路由表。这种方式被称为 Policy-based 。但是在实际配置中,我们可能更倾向于使用传统的配置思路,即,使用路由表或防火墙规则将特定流量发送至特定端口,并将流经此端口的所有数据加密。这种方法被称为 Route-based VPN。一些优点有:
- 在路由表中统一管理转发状态而不用反复调试 Traffic selector 的匹配问题。
- 可以直接在接口上抓明文包,以及设置 MTU。
一些常见配置使用 GRE 或 L2TP 等隧道协议来创建接口,然后用 IPSec 加密整个隧道。strongSwan 自版本 5.8.0,Linux 自版本 4.19 起支持一种新的 xfrm 接口类型,它专门用于给 IPSec 创建一个接口以方便实现 Route-based VPN,并且不像 GRE 或 L2TP 那样需要浪费额外的数据包头。Xfrm 接口可以使用 iproute2 工具包创建,也可以用 systemd-networkd 之类的网络管理工具。
1 | ip link add xfrm0 type xfrm if_id 700 |
修改 strongSwan 配置文件:
1 | connections { |
Xfrm 接口会对所有数据包加上一个特殊的 XFRM_IF_ID 标记,内核中的 xfrm 规则会匹配这一 id,进而加密对应流量。注意路由规则和 TS 规则需要同时满足才加密流量。内核中的 if_id 配置可以用命令查看:
1 | root# ip xfrm policy |
Netfilter
关于 IPSec 数据包与 netfilter 系统的交互,推荐阅读以下两篇文章:
此处仅作备忘:
- 入站 ESP 包:先经过 PREROUTING 和 INPUT, 然后解密。
- 解密后的明文包:重新通过 PREROUTING,发往 INPUT 或 FORWARD。
- 出站明文包:在经过 OUTPUT 或 FORWARD 前进行 xfrm policy 匹配,然后发往 POSTROUTING,然后加密。
- 加密后的密文包:经过 OUTPUT 和 POSTROUTING,离开本机。
- 在不使用 xfrm 接口的情况下,直接在物理接口上抓包可以看到入站密文、入站明文、出站密文,但是看不到出站明文。
- 密文包可以用
meta l4proto espnftable 规则匹配。 - 在 PREROUTING / INPUT / FORWARD 中,使用
ipsec in <...>或meta ipsec可以匹配解密后的明文包。 - 在 FORWARD / OUTPUT / POSTROUTING 中,使用
ipsec out <...>或rt ipsec可以匹配将要被加密的明文包。
例子:如果因为某些原因 strongSwan 没有正确启动,明文流量可能未经加密就被发送,使用 nftables 阻止所有发往 70.0.0.1 但是未经加密的数据包:
1 | ip daddr 70.0.0.1 rt ipsec missing counter drop |
例子:在不使用 xfrm 接口的情况下,捕获所有发往 eth0 的尚未加密的 IPSec 出站包。抓包程序需使用 nflog 接口 tcpdump -i nflog:5。官方文档参考 Taking Traffic Dumps on Linux
1 | meta oifname eth0 rt ipsec exists log group 5 |