IPSec 实战与排错 — ip xfrm、strongSwan 与隧道故障定位

Wireshark 抓 ESP/IKE、ip xfrm 与 swanctl 命令、隧道不通与 MTU/NAT 故障排查 / 网络层安全 / 协议号 50/51 / RFC 4301

这篇你能学到

  • 抓包时先看 IKE 还是先看 ESP、每个 NOTIFY 通知(NO_PROPOSAL_CHOSENTS_UNACCEPTABLE 等)分别指向什么配置错误。
  • ip xfrmswanctlipsec statusall 查隧道状态与内核计数器,判断问题出在控制平面还是数据平面。
  • 处理三类最典型的 IPSec 故障:隧道建不起来、隧道 UP 却 ping 不通、小包通大包卡——以及它们各自的固定套路。

抓包观察

Wireshark 显示过滤式

这些过滤式能干什么:把"谈判过程"(IKE)和"实际数据"(ESP)分开看。建隧道失败就盯 isakmp 系列,隧道建好了但流量不通就盯 esp 系列。

目的过滤表达式
所有 IKE 协商流量isakmp
只看 IKEv2isakmp.version == 0x20
IKE_SA_INIT 交换isakmp.exchangetype == 34
IKE_AUTH 交换isakmp.exchangetype == 35
CREATE_CHILD_SAisakmp.exchangetype == 36
INFORMATIONAL(含 DPD/删除)isakmp.exchangetype == 37
所有 ESP 包esp
按 SPI 过滤某条 SAesp.spi == 0xc0a80101
看 ESP 序列号(查重放)esp.sequence
AH 包ah
原始协议号方式过滤ip.proto == 50(ESP)、ip.proto == 51(AH)
NAT-T 封装的 ESPudp.port == 4500
IKE 与 NAT-T 一起看udp.port == 500 || udp.port == 4500
ICMP 需要分片(MTU 问题)icmp.type == 3 && icmp.code == 4

典型字段说明

排查隧道建立失败时,只看 IKE,不看 ESP。 顺序如下:

  1. isakmp.exchangetype == 34:是否有 IKE_SA_INIT 响应
    • 无响应 → UDP 500 被防火墙拦、对端地址错、对端服务未起。
    • 响应中带 NOTIFY: NO_PROPOSAL_CHOSEN阶段 1 算法提议无交集(加密/完整性/PRF/DH 组)。
    • 响应中带 NOTIFY: INVALID_KE_PAYLOAD → DH 组不匹配,响应方会提示它期望的组号。
    • 出现 NAT_DETECTION_* 载荷 → 路径上有 NAT,后续应切到 UDP 4500。
  2. isakmp.exchangetype == 35:IKE_AUTH 阶段
    • AUTHENTICATION_FAILED → 预共享密钥不一致,或证书/ID 不匹配。
    • TS_UNACCEPTABLE流量选择符(Traffic Selector)不匹配,即两端配置的本端/对端子网对不上。
    • NO_PROPOSAL_CHOSEN 出现在此阶段 → 阶段 2(ESP)算法提议无交集。
  3. 数据不通时看 esp
    • 只见发出、不见回包 → 对端未建 SA、回程路由缺失,或中间设备丢弃协议号 50。
    • esp.sequence 一直是 1、2、3 且不增长 → 出方向没流量命中策略,检查 SPD/路由。

常用命令 / 配置

Linux 内核 XFRM 框架(发行版通用,最直接)

这组命令能干什么:绕开所有 VPN 软件,直接问内核"你现在到底建了哪几条加密通道、跑了多少包、丢包丢在哪一步"。这是判断"问题在配置还是在网络"的最快路径。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 查看所有 SA(每条隧道应成对出现:出方向 + 入方向)
ip xfrm state
ip -s xfrm state # 带包/字节统计,判断有没有真流量
ip xfrm state list src 1.1.1.1 dst 2.2.2.2

# 查看安全策略(SPD)
ip xfrm policy
ip -s xfrm policy

# 查看 IPSec 相关错误计数(丢包原因的第一现场)
ip -s xfrm state | grep -A2 'replay\|error'
cat /proc/net/xfrm_stat # XfrmInNoStates / XfrmInStateSeqError 等

# 实时监听 SA 建立/删除事件
ip xfrm monitor

# 清空所有 SA 与策略(谨慎:会立刻中断隧道)
ip xfrm state flush
ip xfrm policy flush

/proc/net/xfrm_stat 关键计数含义:

计数器含义
XfrmInNoStates收到 ESP 包但找不到对应 SA(对端已 rekey、本端 SA 已删)
XfrmInStateSeqError抗重放检查失败(乱序超窗口或真重放)
XfrmInStateProtoError协议解析或 ICV 校验失败
XfrmOutNoStates出方向命中策略但无 SA(IKE 未协商成功)
XfrmOutPolBlock被 SPD 的 DISCARD 策略丢弃
XfrmInTmplMismatch入方向包与策略模板不匹配(选择符对不上)

strongSwan(主流开源实现)

这组命令能干什么:从 VPN 守护进程的视角看隧道——加载了哪些连接配置、当前有几条 SA 活着、手动把某条隧道拉起来或拆掉、以及把日志级别调高看协商细节。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# ── 新版 swanctl(vici 接口,推荐)──
swanctl --list-conns # 已加载的连接配置
swanctl --list-sas # 当前 IKE SA 与 Child SA 状态
swanctl --initiate --child net-net # 手动发起某条隧道
swanctl --terminate --ike home # 拆除某条 IKE SA
swanctl --load-all # 重载 swanctl.conf 配置
swanctl --stats # 守护进程统计

# ── 旧版 ipsec 命令(starter 方式)──
ipsec status
ipsec statusall # 最详细,排错首选
ipsec up net-net
ipsec down net-net
ipsec restart
ipsec listcerts # 查看已加载证书

# 提升日志级别后看协商细节
journalctl -u strongswan -f
# 或在 strongswan.conf 中:charon { filelog { /var/log/charon.log { default = 2 ike = 3 } } }

strongSwan swanctl.conf 站点到站点示例

这段配置能干什么:把两个分公司的内网(10.1.0.0/16 与 10.2.0.0/16)用一条 IKEv2 隧道打通。重点看三处——proposals(阶段 1 算法,两端必须有交集)、local_ts/remote_ts(子网定义,A 的 local 必须等于 B 的 remote)、esp_proposals(阶段 2 算法,带 modp 即启用 PFS)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
connections {
    site-a-to-b {
        version = 2 # 使用 IKEv2
        local_addrs = 203.0.113.1
        remote_addrs = 198.51.100.1
        proposals = aes256-sha256-modp2048 # IKE SA 算法提议
        rekey_time = 4h
        dpd_delay = 30s # 死对等体检测间隔

        local {
            auth = psk
            id = 203.0.113.1
        }
        remote {
            auth = psk
            id = 198.51.100.1
        }
        children {
            net-net {
                local_ts = 10.1.0.0/16 # 本端受保护子网
                remote_ts = 10.2.0.0/16 # 对端受保护子网
                esp_proposals = aes256gcm16-modp2048 # 带 modp 即启用 PFS
                mode = tunnel
                start_action = trap # 有流量时自动触发协商
                rekey_time = 1h
            }
        }
    }
}
secrets {
    ike-site-b {
        id = 198.51.100.1
        secret = "ThisIsAStrongPreSharedKey"
    }
}

连通性与路径验证

这组命令能干什么:验证"数据平面"这一半——用内网源地址发包看能不能命中策略、二分法找出隧道真正能扛多大的包、确认防火墙放行了 UDP 500/4500 和协议号 50/51、以及用 MSS 钳制这剂"大包不通万能药"。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 用内网源地址 ping,确保流量能命中 SPD 策略
ping -I 10.1.0.1 10.2.0.1

# MTU 探测:找出隧道能承载的最大不分片包
ping -M do -s 1400 -I 10.1.0.1 10.2.0.1 # 逐步减小 1400 直到通
tracepath 10.2.0.1

# 确认防火墙放行(iptables)
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
iptables -A INPUT -p ah -j ACCEPT

# 隧道内 TCP MSS 钳制(解决大包不通的万能药)
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

# 检查是否开启转发
sysctl net.ipv4.ip_forward

# nmap 探测对端 IKE 服务
nmap -sU -p 500,4500 198.51.100.1

Wireshark 解密 ESP

这一步能干什么:把抓到的密文 ESP 包还原成隧道内的明文 IP 包,用来确认"内层到底跑的是什么流量、源目地址对不对"。

编辑 → 首选项 → Protocols → ESP 中勾选 Attempt to detect/decode encrypted ESP payloads,并在 ESP SAs 表中填入 ip xfrm state 输出的加密密钥与认证密钥(十六进制,带 0x 前缀),即可看到隧道内的明文包。

常见故障与排错

结论先行:一眼看懂每个现象在说什么

  • IKE_SA_INIT 无响应 —— 先记住结论:包根本没到对端,或对端没在听,属于网络可达性问题,先别查算法配置。
  • NO_PROPOSAL_CHOSEN(阶段 1) —— 先记住结论:两端算法列表没有交集,谈判在第一步就崩了。
  • INVALID_KE_PAYLOAD —— 先记住结论:DH 组选错了,而且响应方会明确告诉你它想要哪个组号。
  • AUTHENTICATION_FAILED —— 先记住结论:身份没验过,密钥/证书/ID 三者之一对不上。
  • TS_UNACCEPTABLE —— 先记住结论:两端画的子网范围对不上,这是最常见的配置错误。
  • 隧道 UP 但 ping 不通 —— 先记住结论:控制平面成功不代表数据平面通,问题在路由、转发开关或 NAT 抢跑。
  • 小包通、大包/HTTP 卡住 —— 先记住结论:这是 MTU 问题,不是加密问题,加壳后包超了路径 MTU 而 PMTUD 又失效了。
  • NAT 后隧道建不起来或几分钟后断 —— 先记住结论:NAT-T 没生效或映射被回收了
  • 用 AH 完全不通 —— 先记住结论:AH 和 NAT 天生互斥,不是配置问题,是协议设计使然。
  • 隧道每隔固定时间断一次 —— 先记住结论:断在 rekey 那一刻,两端生存期或 PFS 组不一致。
  • XfrmInStateSeqError 持续增长 —— 先记住结论:抗重放窗口把正常的乱序包误杀了(也可能是真重放)。
  • XfrmInNoStates 增长 —— 先记住结论:收到的包属于一条本端已经不存在的 SA,两端换钥匙没同步。
  • 对端重启后隧道半死(单向通) —— 先记住结论:一端的 SA 还留着、另一端已经清空,缺少探活机制。

详细排查表(现象 / 可能原因 / 排查方法)

现象可能原因排查方法
IKE_SA_INIT 无响应UDP 500 被中间防火墙/云安全组拦截;对端 IP 写错;对端 charon 未运行nmap -sU -p 500 对端;两端同时抓 udp.port==500 看包有没有出去/进来
NO_PROPOSAL_CHOSEN(阶段 1)IKE 算法提议无交集(加密/完整性/PRF/DH 组)对齐 proposals;日志里响应方会列出自己支持的提议
INVALID_KE_PAYLOADDH 组不一致响应方 NOTIFY 中会给出期望的组号,按其修改
AUTHENTICATION_FAILEDPSK 不一致;证书过期/CA 不信任;ID 类型与配置的 leftid/rightid 不符核对 secrets;ipsec listcerts;确认 NAT 后一端应使用 FQDN 而非 IP 作 ID
TS_UNACCEPTABLE两端 local_ts / remote_ts 子网定义对不上(最常见配置错误)A 的 local 必须等于 B 的 remote,反之亦然;注意掩码位数与 0.0.0.0/0 的处理
隧道 UP 但 ping 不通① 路由未指向隧道 ② 未开 ip_forward ③ NAT 规则把内网流量先 SNAT 了导致不命中 SPD ④ 回程路由缺失ip route get 10.2.0.1ip -s xfrm state 看出方向计数是否增长;在 nat POSTROUTING 中为隧道流量加 -j ACCEPT 例外
小包通、大包/HTTP 卡住MTU 问题:加了 ESP 头后超出路径 MTU,且 ICMP “需要分片” 被拦ping -M do -s N 二分找上限;配 TCPMSS --clamp-mss-to-pmtu;隧道口设 mtu 1400
NAT 后隧道建不起来或几分钟后断未启用 NAT-T;NAT 映射超时抓包确认是否切到 UDP 4500;检查 NAT_DETECTION 载荷;开启 keepalive(strongSwan keep_alive
用 AH 完全不通AH 的 ICV 覆盖 IP 头,NAT 改地址后校验必然失败NAT 环境改用 ESP(生产环境本就应优先 ESP)
隧道每隔固定时间断一次rekey 失败:两端 lifetime/PFS 组不一致;一端不支持 CREATE_CHILD_SA日志搜 rekey;对齐 rekey_timeesp_proposals 中的 DH 组
XfrmInStateSeqError 持续增长抗重放窗口过小 + 网络乱序(多路径/QoS)增大 replay_window(strongSwan replay_window = 128)或排查底层乱序
XfrmInNoStates 增长对端已 rekey 生成新 SPI,本端旧 SA 已删检查两端 lifetime 差距;缩小差异并设置 rekey 提前量
对端重启后隧道半死(单向通)一端 SA 还在,另一端已清空开启 DPD(dpd_delay + dpd_action = restart)自动检测并重建

通用排查顺序两端能否 IP 可达UDP 500/4500 是否放行IKE_SA_INIT 有无响应IKE_AUTH 是否通过认证TS 是否匹配ip xfrm state 是否成对存在出方向计数是否增长路由/NAT/forwardMTU

与其他协议对比

维度IPSecTLSWireGuardGRE(裸)L2TP(裸)
工作层次网络层(IP)传输层之上网络层(UDP 承载)网络层封装二层隧道
加密✅ ESP✅ 固定 ChaCha20-Poly1305❌ 无❌ 无
认证方式PSK / X.509 证书 / EAPX.509 证书(PKI)静态公钥(类 SSH)PPP 用户认证
对应用透明✅ 完全透明❌ 需应用支持✅ 透明
承载IP 协议号 50/51TCPUDP(可自定义端口)IP 协议号 47UDP 1701
NAT 穿越需 NAT-T(AH 不可)天然支持天然支持需额外处理需配合 IPSec
组播/动态路由隧道模式默认不支持组播不适用不支持✅ 支持
配置复杂度高(参数众多)
典型场景企业站点互联、云 VPC 互联Web/API 加密个人与轻量组网多协议封装拨号接入

生产常见组合:GRE over IPSec(GRE 提供组播与动态路由能力,IPSec 提供加密),或 VTI/route-based IPSec(把隧道抽象成一个虚拟接口,路由更自然)。

速查表 / 常见面试题

核心数字速查

项目
ESP 协议号50
AH 协议号51
IKE 端口UDP 500
NAT-T 端口UDP 4500
IKEv2 交换类型34=IKE_SA_INIT,35=IKE_AUTH,36=CREATE_CHILD_SA,37=INFORMATIONAL
IKEv2 建隧道消息数4 条(2 次往返)
IKEv1 主模式 + 快速模式6 + 3 = 9 条
抗重放窗口默认64 位(可配 128/1024)
ESP 隧道模式典型开销约 50–73 字节
常见隧道口 MTU 设置1400(以太网 1500 环境下的保守值)

常见面试题

  1. AH 与 ESP 的区别?为什么生产上几乎只用 ESP? AH 只提供完整性与数据源认证,不加密;ESP 同时提供加密与认证。AH 的 ICV 覆盖 IP 头,与 NAT 天然冲突;ESP 的 ICV 不覆盖外层 IP 头,配合 NAT-T 可穿越 NAT。ESP 的能力是 AH 的超集,所以 AH 已基本退役。

  2. 传输模式与隧道模式怎么选? 主机到主机直连(如两台服务器间加密)用传输模式,开销小;网关到网关、需要隐藏内网拓扑、需要为整个子网提供保护时用隧道模式——这也是 VPN 的标准做法。

  3. SA 为什么是单向的? 因为加解密的密钥、序列号、算法在两个方向上可以不同,且单向建模让状态机更简单、更易做抗重放。因此一条双向隧道至少有 2 个 IPSec SA。

  4. SPI 由谁分配?接收方分配。A 告诉 B “你发给我的包请打上 SPI=X”,B 在发包时填入该 SPI,A 收到后据此查表定位 SA。

  5. IKEv2 相比 IKEv1 的改进? 消息数从 9 条降到 4 条;原生集成 NAT-T、DPD、EAP;支持 MOBIKE 地址漫游;请求/响应严格配对且带 Message ID,状态机更健壮;抗 DoS 的 Cookie 机制标准化。

  6. 为什么 IPSec 隧道 UP 了却 ping 不通? 最常见四类:路由没指过去、ip_forward 未开、NAT 规则抢先把内网流量 SNAT 导致不命中 SPD、两端 TS(流量选择符)虽协商成功但实际发包的源 IP 不在保护子网内。

  7. 为什么 IPSec 隧道里大包会卡住? 加了 ESP 头后包超出路径 MTU,需要分片;若路径上 ICMP “Fragmentation Needed” 被防火墙拦截,PMTUD 失效形成黑洞。解法:TCP MSS 钳制 + 调低隧道接口 MTU。

  8. PFS 在 IPSec 里指什么? Child SA rekey 时是否重新做一次 DH 交换。开启后每对 SA 的密钥彼此独立,单个密钥泄露不波及其他;代价是每次 rekey 多一次 DH 运算。两端 PFS 组必须一致。

  9. IPSec 和 TLS 该选哪个? 需要保护"整个网络之间的全部流量、且不能改应用"选 IPSec(企业组网);需要保护"某个具体服务的连接、要穿公网和 NAT、要用 PKI 生态"选 TLS(互联网服务)。二者不互斥,可叠加。