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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
connections {
conn {
# 忽略其他配置字段
children {
child_sa {
# 忽略其他配置字段
local_ts = 0.0.0.0/0 # 路由表负责决定要转发什么流量,TS 可以允许所有。
remote_ts = dynamic # 如果有多个对端,仍然需要 remote_ts 匹配对端 IP
# 以应用正确的 CHILD_SA
}
}
if_id_in = 700 # 设置所有 CHILD_SA 使用的 XFRM IF_ID
if_id_out = 700 # in, out 可以不同,但一般没必要
}
}

Xfrm 接口会对所有数据包加上一个特殊的 XFRM_IF_ID 标记,内核中的 xfrm 规则会匹配这一 id,进而加密对应流量。注意路由规则和 TS 规则需要同时满足才加密流量。内核中的 if_id 配置可以用命令查看:

1
2
3
4
5
6
root# ip xfrm policy
src 0.0.0.0/0 dst 0.0.0.0/0
dir out priority 399999 ptype main
tmpl src 10.0.0.1 dst 10.0.0.2
proto esp spi 0xc4f5e6d5 reqid 1 mode tunnel
if_id 0x2bc

Netfilter

关于 IPSec 数据包与 netfilter 系统的交互,推荐阅读以下两篇文章:

此处仅作备忘:

  • 入站 ESP 包:先经过 PREROUTING 和 INPUT, 然后解密。
  • 解密后的明文包:重新通过 PREROUTING,发往 INPUT 或 FORWARD。
  • 出站明文包:在经过 OUTPUT 或 FORWARD 前进行 xfrm policy 匹配,然后发往 POSTROUTING,然后加密。
  • 加密后的密文包:经过 OUTPUT 和 POSTROUTING,离开本机。
  • 在不使用 xfrm 接口的情况下,直接在物理接口上抓包可以看到入站密文、入站明文、出站密文,但是看不到出站明文。
  • 密文包可以用 meta l4proto esp nftable 规则匹配。
  • 在 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