2257 字
约 7 分钟
14
S02-X13 · IPsec:IKE 协商、ESP 封装与隧道 MTU

同样是"把链路加密",TLS 在 socket 之上,只保护某个应用的流量;IPsec 在网络层之下,保护的是整个 IP 包。这个位置差异带来两个直接后果:对上层协议完全透明(TCP、UDP、ICMP 一起走),以及必须自己面对封装后变小的 MTU。配置 IPsec 出的问题,八成不在加密算法上,而在协商参数对不上或 MTU 被吃掉。


1. 位置决定能力:TLS 与 IPsec 的差别

维度 TLS IPsec
工作层次 传输层之上(应用可感知) 网络层(IP 之上)
保护对象 单条连接的数据流 IP 包,含所有上层协议
身份 证书 + 域名(SNI) 预共享密钥 / 证书 / EAP,绑定 IP 或 ID
对应用的要求 需支持 TLS 应用无感
典型实现 Nginx / OpenSSL 内核 XFRM + IKE 守护进程
失效表现 握手失败、证书告警 包被丢、隧道不通、路由黑洞

第二条最关键:IPsec 由内核的数据面 + 用户态的协商面两部分组成。内核负责加密解密与封装(XFRM 子系统),守护进程只负责谈参数、下发 SA。所以"配置改了没生效"通常要看两边:swanctl --list-sas 和 ip xfrm state。


2. AH 与 ESP:两个协议保护的范围不同

项 AH(IP 协议号 51) ESP(IP 协议号 50)
完整性覆盖 整个 IP 包,含外层 IP 头 仅 ESP 载荷(不含外层 IP 头)
加密 不提供 提供
NAT 穿越 不可行(IP 头被改即校验失败) 可行(NAT-T 用 UDP 4500 封装)
典型用途 极少,仅完整性验证场景 绝大多数 VPN
与隧道模式组合 支持但无实际意义 标准组合

实践中"IPsec = ESP"。AH 在 NAT 环境下直接失效,因为 NAT 会改写源 IP,而 AH 的 ICV 覆盖了该字段——这也是 NAT-T 存在的原因。

传输模式(Transport):
  [IP 头][ESP 头][加密的 TCP/UDP 载荷][ESP 尾][ICV]
隧道模式(Tunnel):
  [新 IP 头][ESP 头][加密的 原始IP头+载荷 ][ESP 尾][ICV]
模式 是否新增 IP 头 适用 代价
Transport 否 主机到主机、端到端加密 原 IP 头暴露,路由需可达
Tunnel 是(20/40 字节) 网关到网关、站点互联 多一层头,MTU 更紧

3. IKEv2 的三段协商

IKE 负责"谈参数",本身跑在 UDP 500 上;一旦检测到 NAT,后续 ESP 改走 UDP 4500。

阶段 交换 产出 常见失败点
IKE_SA_INIT 两条消息 协商加密套件、交换 DH、建立 IKE SA 算法集无交集、DH 组不匹配
IKE_AUTH 两条消息 身份认证、建立首个 CHILD_SA PSK 不一致、ID 不匹配、证书链不全
CREATE_CHILD_SA 可选、随时 新 SA、重协商密钥 流量选择器不匹配
概念 含义 排查命令
IKE SA 控制通道,双向一对 swanctl --list-sas
CHILD_SA 数据通道,每个方向一对 SPI ip xfrm state
Proposal 算法组合(加密 + 完整性 + PRF + DH) 对比两端 proposals = 行
Traffic Selector 哪些源/目的网段进隧道 local_ts / remote_ts
SPI 安全参数索引,标识一个 SA ip xfrm state 的 spi 字段

协商铁律:两端 proposal 必须有交集,且顺序不影响结果。只要有一端把 aes256gcm16-prfsha256-ecp256 写成 aes128-sha1-modp1024 这类旧组合,IKE_AUTH 就会停在 NO_PROPOSAL_CHOSEN。


4. 一份可用的 strongSwan 配置

下面按 strongSwan 5.9 的 swanctl 语法写,站点到站点、两端都是固定公网 IP 的场景。

# /etc/swanctl/conf.d/site.conf
connections {
  site-b {
    version = 2
    local_addrs  = 203.0.113.10
    remote_addrs = 198.51.100.20
    local {
      auth = psk
      id   = 203.0.113.10
    }
    remote {
      auth = psk
      id   = 198.51.100.20
    }
    proposals = aes256gcm16-prfsha256-ecp256, aes128-sha256-modp2048
    children {
      net {
        local_ts  = 10.10.0.0/24
        remote_ts = 10.20.0.0/24
        esp_proposals = aes256gcm16-ecp256
        dpd_delay = 30s
        start_action = trap
      }
    }
  }
}

secrets {
  ike-site-b { secret = "REPLACE_WITH_PSK" }
}
# 生效与观察
swanctl --load-all
swanctl --initiate --child net
swanctl --list-conns
swanctl --list-sas

# 内核侧确认 SA 与策略
ip xfrm state list
ip xfrm policy list

内核数据面也可以手工下发,用来验证"配置问题还是内核问题":

ip xfrm state add src 203.0.113.10 dst 198.51.100.20 proto esp spi 0x1000 \
  reqid 1 mode tunnel aead "rfc4106(gcm(aes))" 0x000102030405060708090a0b0c0d0e0f10111213 128
ip xfrm policy add dir out src 10.10.0.0/24 dst 10.20.0.0/24 \
  tmpl src 203.0.113.10 dst 198.51.100.20 proto esp mode tunnel

如果手工 SA 能通、swanctl 建的不通,问题就在协商侧(proposal、ID、selector);两者都不通则是路由、防火墙或 MTU。


5. 放行与 MTU:两处最容易漏的配置

规则 协议/端口 说明
IKE UDP 500 初始协商,必须双向可达
NAT-T UDP 4500 检测到 NAT 后 ESP 被封进 UDP
ESP IP 协议 50 非 NAT 场景的数据面
AH IP 协议 51 仅使用 AH 时需要
ICMP echo/reply 建议放行,用来验 MTU
# nftables 写法(firewalld 也可用 rich rule 表达)
nft add rule inet filter input udp dport {500, 4500} accept
nft add rule inet filter input ip protocol esp accept

封装开销是 MTU 问题的根源。按典型量级估算:

封装组合 额外字节(约)
IPv4 + ESP(AES-GCM,含 IV 与 ICV) 50–60
IPv4 隧道模式(再加外层 20 字节 IP 头) 70–80
IPv6 隧道模式(外层 40 字节) 90–100
再叠一层 UDP 封装(NAT-T) 再加 8

若链路 MTU 是 1500,隧道内可用 MTU 只剩 1400 出头,对应 TCP MSS 约 1360。不处理就会出现"能 ping 通小包、大包全丢"的经典现象:ssh 卡在登录、curl 卡在响应体。

# 网关侧钳制 MSS,让两端自行收敛
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

内核 XFRM 也支持在策略上做 PMTU 处理,但对端不配合时仍然要靠 MSS clamp。


6. 排错:六种典型故障

现象 常见原因 定位
协商停在 NO_PROPOSAL_CHOSEN 两端 proposal 无交集 swanctl --list-conns 对比算法串
AUTHENTICATION_FAILED PSK 不一致、ID 写错 核对 secrets 与 local.id/remote.id
SA 建起来但 ping 不通 traffic selector 不覆盖实际网段 ip xfrm policy list 看 src/dst
小包通、大包丢 MTU/MSS 未收敛 ping -M do -s 1400 逐步逼近
一段时间后断,重建又通 DPD 未开或重协商失败 开 dpd_delay,看日志重协商记录
只有单向通 一侧策略缺 dir in/dir fwd 两侧都 ip xfrm policy list 对照
NAT 后 ESP 不通 未启用 NAT-T 确认 4500 放行、encapsulation 设置

日志入口固定在这几处:journalctl -u strongswan、swanctl --log(实时)、内核侧 dmesg | grep -i xfrm。把三层分开看——协商日志、SA 表、包计数(ip -s xfrm state 有字节计数)——能快速判断断在哪一层。


7. 边界:什么时候 IPsec 不是好选择

场景 更适合的方案 理由
少量客户端接入办公网 WireGuard / OpenVPN 配置量级小得多,NAT 友好
只需要保护 HTTP 流量 TLS + mTLS 无需动网络层,审计更细
跨云多租户互联 云厂商 VPN 网关 / 专线 托管方处理协商与 MTU 收敛
需要按应用做策略 服务网格 mTLS IPsec 只能按 IP/端口粒度
客户端在频繁变动的移动网络 WireGuard(UDP 单端口) IPsec 的多端口与 NAT 检测更易断

一条容易被忽略的边界:IPsec 保护的是"包在链路上不被看/被改",它不解决"谁有权限访问哪个服务"。访问控制仍要靠安全组、防火墙规则和应用鉴权,把这两件事混在一起谈,往往导致隧道建好了但权限模型一片空白。


8. 自测

  1. 为什么 AH 在 NAT 环境下不可用,而 ESP 可以?
  2. 隧道模式与传输模式在报文结构上的差别是什么,各自多出多少字节?
  3. IKE_SA_INIT 与 IKE_AUTH 各解决什么问题?NO_PROPOSAL_CHOSEN 出现在哪一步?
  4. swanctl --list-sas 有输出但业务不通,下一步该查什么表?
  5. 链路 MTU 1500,IPv4 隧道模式下隧道内可用 MTU 大致是多少?
  6. 手工 ip xfrm state 能通、守护进程建的不通,说明问题在哪一层?
S02-X13 · IPsec:IKE 协商、ESP 封装与隧道 MTU
https://www.clxhxhhr.top/posts/6028/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。