环境与现象
- Windows 客户端连接 IKEv2 时提示 “服务器无响应”
- VPN 服务器地址:
192.168.1.200(飞牛OS Docker 部署) - 客户端地址:
192.168.1.201,局域网互通正常(ping 0ms)
| 项目 | 详情 |
|---|---|
| 宿主机 | 飞牛OS |
| 部署方式 | Docker 容器 ipsec-vpn-server |
| IKE 软件 | Libreswan 5.3.1(IKE daemon: pluto) |
| L2TP 软件 | xl2tpd 1.3.18 |
| 容器权限 | --privileged |
排查过程
第一步:网络层端口探测
在客户端使用多种工具测试服务器 UDP 500(ISAKMP)和 UDP 4500(NAT-T)端口:
# ncat 测试
ncat -u -v -z -w 3 192.168.1.200 500
ncat -u -v -z -w 3 192.168.1.200 4500
# Python socket 空探测
python3 -c "
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 0))
sock.sendto(b'', ('192.168.1.200', 500)) # 发空包
# 收到 ICMP port-unreachable → 端口关闭
# 超时无 ICMP 错误 → 端口开放
"结果:
| 端口 | 状态 | 说明 |
|---|---|---|
| UDP 500 (ISAKMP) | ❌ 关闭 | 服务器返回 ICMP Port Unreachable |
| UDP 4500 (NAT-T) | ✅ 开放 | 无 ICMP 错误返回 |
IKEv2 协商流程是客户端先向 UDP 500 发起 IKE_SA_INIT 请求,500 不通则协商根本无法开始。这就是 Windows 报"服务器无响应"的直接原因。
第二步:定位问题到 IKE Daemon
进入 Docker 容器检查进程和端口监听:
# 容器内只有 xl2tpd,没有 IKE 进程在监听
$ netstat
(空列表——没有任何端口监听信息)
$ ps aux
root 1 xl2tpd -D # L2TP 隧道进程
root 822 /bin/sh /usr/.../ipsec/_plutorun --config /etc/ipsec.conf --nofork
root 823 sleep 10 # ← 关键线索!发现关键问题:
_plutorun 是 Libreswan 的 watchdog 脚本。看到 _plutorun + sleep 10 同时存在,说明它进入了一个死循环:尝试启动 pluto → 立即崩溃 → 等 10 秒 → 重试 → 无限循环。
$ ipsec status
ERROR: ipsec whack: Pluto is not running (no "/run/pluto/pluto.ctl")Pluto 根本没在运行。
第三步:手动启动 Pluto 抓崩溃原因
$ /usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf --nofork
Pluto is starting ...
Aborted (core dumped)Pluto 直接 SIGABRT 崩溃。用 strace 追踪系统调用,定位到崩溃前的最后操作为:
$ strace -f /usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf --nofork 2>&1 | tail -50
[pid 5625] socket(AF_NETLINK, SOCK_DGRAM|SOCK_CLOEXEC, NETLINK_XFRM) = -1 EPROTONOSUPPORT (Protocol not supported)
^^^^^^^^^^^^^^^^
协议不受支持!NETLINK_XFRM 套接字创建失败,pluto 随即调用 tgkill(getpid(), SIGABRT) 自杀。
第四步:确认宿主机内核状态
NETLINK_XFRM 协议由内核模块 xfrm_user 提供。检查宿主机:
$ cat /proc/config.gz | gunzip | grep CONFIG_XFRM_USER
CONFIG_XFRM_USER=m # ← 内核编译为模块,支持!
$ lsmod | grep xfrm
xfrm_interface # ← 有这个
xfrm6_tunnel # ← 有这个
tunnel4 # ← 有这个
tunnel6 # ← 有这个
# 但是...
# xfrm_user 不在列表中! ← 模块存在但未加载结论: 飞牛OS 内核编译了 CONFIG_XFRM_USER=m(模块),但 xfrm_user 模块没有被加载。Pluto 需要这个模块提供 NETLINK_XFRM 用户态接口来管理 IPsec SA 和策略,拿不到就崩溃。
xl2tpd(正常) → L2TP 用 l2tp_core/l2tp_ppp 模块 ✅
pluto(崩溃) → IKE 需要 xfrm_user 模块 ❌ 未加载
解决方案
# 1. 加载 xfrm_user 内核模块
sudo modprobe xfrm_user
# 2. 确认加载成功
lsmod | grep xfrm_user
# 3. 重启 Docker 容器
sudo docker restart ipsec-vpn-server
# 4. 设置开机自动加载,避免重启后失效
echo "xfrm_user" | sudo tee /etc/modules-load.d/ipsec.conf执行后,pluto 成功启动,UDP 500 和 4500 端口正常监听,Windows 客户端顺利连接。
总结
IKEv2 VPN 依赖链条:
Windows 客户端
│ UDP 500 (IKE_SA_INIT)
▼
pluto (Libreswan IKE daemon)
│ socket(AF_NETLINK, ..., NETLINK_XFRM)
▼
xfrm_user 内核模块 ← 这一步断了
│
▼
Linux 内核 IPsec 栈 (XFRM)
l2tp_core/l2tp_ppp→ xl2tpd 使用,和 IKE 无关xfrm_interface/xfrm6_tunnel→ IPsec 接口/隧道框架,和用户态配置接口无关xfrm_user→ 用户态程序通过 netlink 配置 IPsec 的接口,pluto/charon 启动必须依赖它
这三个是不同东西,模块名相近容易混淆。本次问题就是前两个已加载,唯独缺了真正需要的 xfrm_user。