第344篇:IPsec VPN 协商失败与排障实战案例

关键词

IPsec VPN、IKE、ISAKMP、SA、NAT-T、DPD、ESP、AH、加密算法、认证、野蛮模式、主模式


一、案例背景

1.1 故障现象

某企业 IPsec VPN 故障:

时间:周二上午 10:00(总部网络变更后) 影响:分支机构无法通过 VPN 访问总部

现象:

影响范围: └─ 分支 A(上海):VPN 断开,无法重连 └─ 分支 B(广州):VPN 断开,无法重连 └─ 分支 C(深圳):VPN 正常 故障表现: └─ VPN 隧道状态显示 DOWN └─ 手动触发 IKE 协商失败 └─ 公网连通性正常(ping 总部公网 IP 通)

1.2 网络拓扑

Hub-Spoke VPN 组网:

      ┌──────────────────────┐
      │   总部(HQ)         │
      │   GW: 202.100.1.1   │
      │   LAN: 10.1.0.0/16  │
      └────────┬─────────────┘
               │ Internet
      ┌────────┴─────────────┐
      │   防火墙(新更换)   │
      │   USG6600            │
      └────────┬─────────────┘
               │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
上海 分支 GW:A 202... 10.2.0 广州 分支 GW:B 202... 10.3.0 深圳 分支 GW:C 202... 10.4.0

变更内容: ┌──────────────────────────────────────────┐ │ 昨天下午总部更换了出口防火墙 │ │ 新防火墙型号:USG6600 │ │ 新防火墙 IP:202.100.1.1(不变) │ │ 新增了 NAT 策略 │ │ 启用了安全配置文件 │ └──────────────────────────────────────────┘


二、故障排查

2.1 基础检查

排查路线:

  第一步:检查公网连通性
  ┌──────────────────────────────────────────┐
  │  从分支 A 测试到总部:                    │
  │  ping 202.100.1.1                        │
  │  └─ 成功!延迟 20ms                      │
  │                                           │
  │  telnet 202.100.1.1 500                  │  # IKE
  │  └─ 连接失败!                           │  ← 问题!
  │                                           │
  │  telnet 202.100.1.1 4500                 │  # NAT-T
  │  └─ 连接失败!                           │  ← 问题!
  │                                           │
  │  结论:公网 ICMP 通,但 UDP 500/4500 不通 │
  └──────────────────────────────────────────┘

  第二步:检查新防火墙配置
  ┌──────────────────────────────────────────┐
  │  # 查看安全策略                           │
  │  display security-policy                 │
  │                                           │
  │  # 发现缺少放通 IKE 流量的策略           │
  │  # 缺省策略是 deny                      │
  │                                           │
  │  # 查看 NAT 策略                          │
  │  display nat-policy                      │
  │  ┌──────────────────────────────────────┐ │
  │  │  NAT 策略对 VPN 流量也做了转换!     │ │
  │  │  src: trust → untrust                │ │
  │  │  action: source-nat                  │ │
  │  │  # 分支发来的 IKE 包被 NAT 了        │ │
  │  │  # 但 IPsec 不能做 NAT(除非 NAT-T)   │ │
  │  └──────────────────────────────────────┘ │
  │                                           │
  │  发现两个问题:                            │
  │  1. 安全策略未放通 IKE(UDP 500/4500)   │
  │  2. NAT 策略对 IKE 流量做了 NAT          │
  └──────────────────────────────────────────┘

2.2 深度排查(为什么深圳分支正常)

第三步:比较正常和异常分支配置

深圳分支(正常)配置: ┌──────────────────────────────────────┐ └──────────────────────────────────────┘ 上海分支(异常)配置: ┌──────────────────────────────────────┐ └──────────────────────────────────────┘ 根因: └─ 上海分支未启用 NAT-T └─ 总部新防火墙对 VPN 流量做了 NAT └─ 没有 NAT-T 时,NAT 会破坏 IKE └─ 和 ESP 报文头 interface GigabitEthernet0/0/1 ip address 202.100.4.1 24 nat enable ipsec policy hq-vpn 1 isakmp transform-set esp-aes256-sha remote-address 202.100.1.1 nat-traversal enable ipsec policy hq-vpn 1 isakmp transform-set esp-aes256-sha remote-address 202.100.1.1 # 未配置 nat-traversal ← 启用了 NAT-T ← 问题!

2.3 IKE 协商阶段分析

IKE 协商流程图(了解各阶段失败原因):

  分支(发起方)                        总部(响应方)
       │                                      │
       │     Phase 1: IKE SA                  │
       │  ───────────────────────             │
       │  1. 策略协商 (SA Init)               │
       │  ──────────────────────────────────  │
       │     加密算法:AES256/SHA256/DH14     │
       │                                     │
       │     可能失败原因:                    │
       │     ❌ 算法不匹配                    │
       │     ❌ NAT-T 未协商                  │
       │     ❌ 认证方式不同                  │
       │     ❌ DH 组不一致                   │
       │                                     │
       │  2. DH 交换 (Key Exchange)          │
       │  ──────────────────────────────────  │
       │     生成共享密钥                     │
       │                                     │
       │     可能失败原因:                    │
       │     ❌ DH 组计算超时                 │
       │     ❌ 防火墙策略拦截                │
       │                                     │
       │  3. 认证 (Auth)                     │
       │  ──────────────────────────────────  │
       │     预共享密钥验证                   │
       │                                     │
       │     可能失败原因:                    │
       │     ❌ PSK 不匹配                    │
       │     ❌ ID 不匹配                     │
       │                                     │
       │     Phase 2: IPsec SA                │
       │  ───────────────────────             │
       │  4. 快速模式 (Quick Mode)           │
       │  ──────────────────────────────────  │
       │     协商感兴趣流                     │
       │                                     │
       │     可能失败原因:                    │
       │     ❌ ACL 不匹配                    │
       │     ❌ 代理 ID 不匹配               │
       │     ❌ 完美前向保密(PFS)不一致     │
       │                                     │
       │  5. IPsec SA 建立                   │
       │  ──────────────────────────────────  │
       │     ESP 加密隧道就绪                │
       └──────────────────────────────────────┘

三、解决方案

3.1 临时恢复

紧急恢复步骤:

  步骤一:放通 IKE 流量
  ┌──────────────────────────────────────────┐
  │  # 在总部新防火墙上放通 IKE             │
  │  system-view                             │
  │  security-policy                         │
  │   rule name permit_ike                   │
  │    source-zone untrust                   │
  │    destination-zone local                │
  │    source-address any                    │
  │    service udp 500                       │
  │    service udp 4500                      │
  │    action permit                         │
  └──────────────────────────────────────────┘

  步骤二:排除 IKE 流量 NAT
  ┌──────────────────────────────────────────┐
  │  # 配置 NAT 策略排除 VPN 流量           │
  │  nat-policy                              │
  │   rule name no_nat_vpn                  │
  │    source-zone trust                    │
  │    destination-zone untrust             │
  │    source-address 10.1.0.0 16           │
  │    destination-address any              │
  │    action no-nat                        │
  │                                          │
  │  # 注意:必须放在 NAT 策略最前面        │
  └──────────────────────────────────────────┘

  步骤三:在分支启用 NAT-T
  ┌──────────────────────────────────────────┐
  │  # 上海分支配置                         │
  │  system-view                             │
  │  ipsec proposal hq-proposal              │
  │   transform esp                          │
  │   esp authentication-algorithm sha2-256  │
  │   esp encryption-algorithm aes-256       │
  │  #                                        │
  │  ipsec policy hq-vpn 1 isakmp            │
  │   security acl 3000                      │
  │   ike-peer hq                           │
  │   proposal hq-proposal                   │
  │   nat-traversal enable                   │  ← 关键!
  └──────────────────────────────────────────┘

3.2 配置对比验证

#!/usr/bin/env python3
"""
IPsec VPN 配置检查与健康诊断工具
"""

import ipaddress
import re


class IPsecConfigValidator:
    """IPsec 配置验证器"""

    def __init__(self, device_name, config_text):
        self.device_name = device_name
        self.config_text = config_text
        self.issues = []
        self.warnings = []

    def check_ike_params(self):
        """检查 IKE 参数"""
        # 检查预共享密钥
        if "pre-shared-key" not in self.config_text:
            self.issues.append("未配置预共享密钥")

        # 检查 IKE 版本
        if "ikev2" not in self.config_text and "ikev1" not in self.config_text:
            self.warnings.append("未指定 IKE 版本,使用默认配置")

        # 检查认证算法
        if "sha2-256" not in self.config_text and "sha1" not in self.config_text:
            self.warnings.append("建议使用 SHA256 或更强的认证算法")

    def check_ipsec_params(self):
        """检查 IPsec 参数"""
        # 检查加密算法强度
        weak_algorithms = ["des", "3des", "aes-128"]
        for algo in weak_algorithms:
            if algo in self.config_text:
                self.warnings.append(
                    f"使用较弱的加密算法: {algo},建议升级"
                )

        # 检查 PFS
        if "pfs" not in self.config_text:
            self.warnings.append("未配置 PFS(完美前向保密)")

    def check_nat_traversal(self):
        """检查 NAT-T 配置"""
        if "nat-traversal" not in self.config_text:
            self.warnings.append("建议启用 NAT-T(NAT 穿越)")

    def check_dpd(self):
        """检查 DPD 配置"""
        if "dpd" not in self.config_text:
            self.warnings.append(
                "未配置 DPD(死对端检测),影响故障切换速度"
            )

    def check_acl(self):
        """检查感兴趣流 ACL"""
        acl_match = re.search(
            r"acl\s+(\d+).*?rule.*?permit\s+ip\s+"
            r"(\S+)\s+(\S+)\s+(\S+)\s+(\S+)",
            self.config_text, re.DOTALL
        )
        if not acl_match:
            self.warnings.append("未找到感兴趣流 ACL 配置")

    def run_all_checks(self):
        """运行所有检查"""
        self.check_ike_params()
        self.check_ipsec_params()
        self.check_nat_traversal()
        self.check_dpd()
        self.check_acl()

        return {
            "device": self.device_name,
            "issues": self.issues,
            "warnings": self.warnings,
            "issue_count": len(self.issues),
            "warning_count": len(self.warnings),
            "status": "CRITICAL" if self.issues else (
                "WARNING" if self.warnings else "HEALTHY"
            )
        }


class VPNHealthChecker:
    """VPN 健康检查器"""

    def __init__(self):
        self.tunnels = {}

    def add_tunnel(self, name, local_ip, remote_ip, status):
        """添加隧道信息"""
        self.tunnels[name] = {
            "local_ip": local_ip,
            "remote_ip": remote_ip,
            "status": status,
            "uptime": 0,
            "in_bytes": 0,
            "out_bytes": 0
        }

    def check_tunnel_status(self):
        """检查隧道状态"""
        results = []
        for name, info in self.tunnels.items():
            status = info["status"]
            results.append({
                "tunnel": name,
                "local": info["local_ip"],
                "remote": info["remote_ip"],
                "status": status,
                "healthy": status == "UP"
            })
        return results

    def generate_diagnosis_report(self, configs):
        """生成诊断报告"""
        report = f"""
IPsec VPN 诊断报告
{'=' * 60}

一、隧道状态
"""
        tunnel_results = self.check_tunnel_status()
        all_healthy = True
        for t in tunnel_results:
            symbol = "✅" if t["healthy"] else "❌"
            report += f"  {symbol} {t['tunnel']}: {t['status']}\n"
            if not t["healthy"]:
                all_healthy = False

        report += f"""
二、配置检查
"""
        for cfg in configs:
            validator = IPsecConfigValidator(cfg["name"], cfg["config"])
            result = validator.run_all_checks()
            symbol = "✅" if result["status"] == "HEALTHY" else "⚠"
            report += f"  {symbol} {cfg['name']}: {result['status']}\n"
            for issue in result["issues"]:
                report += f"    ❌ {issue}\n"
            for warning in result["warnings"]:
                report += f"    ⚠ {warning}\n"

        if not all_healthy:
            report += """
三、排障建议
"""
            report += """  1. 检查防火墙是否放通了 UDP 500/4500
  2. 确认 NAT 策略是否排除了 IKE 流量
  3. 对比两端 IKE 参数是否一致(加密/认证/DH 组)
  4. 确认预共享密钥是否匹配
  5. 检查两端感兴趣流 ACL 是否对应
  6. 启用 NAT-T(如果中间有 NAT 设备)
  7. 配置 DPD 以快速检测对端故障
"""
        return report


def main():
    """主函数"""
    checker = VPNHealthChecker()

    # 模拟隧道状态
    checker.add_tunnel("HQ-Shanghai", "202.100.1.1", "202.100.2.1", "DOWN")
    checker.add_tunnel("HQ-Guangzhou", "202.100.1.1", "202.100.3.1", "DOWN")
    checker.add_tunnel("HQ-Shenzhen", "202.100.1.1", "202.100.4.1", "UP")

    # 模拟配置
    configs = [
        {
            "name": "上海分支",
            "config": """
ipsec proposal hq-proposal
 transform esp
 esp authentication-algorithm sha1
 esp encryption-algorithm aes-256
#
ipsec policy hq-vpn 1 isakmp
 security acl 3000
 ike-peer hq
 proposal hq-proposal
# 缺少 nat-traversal
# 缺少 dpd
"""
        },
        {
            "name": "深圳分支",
            "config": """
ipsec proposal hq-proposal
 transform esp
 esp authentication-algorithm sha2-256
 esp encryption-algorithm aes-256
 pfs dh-group14
#
ipsec policy hq-vpn 1 isakmp
 security acl 3000
 ike-peer hq
 proposal hq-proposal
 nat-traversal enable
 dpd interval 10 retry 3
"""
        }
    ]

    print(checker.generate_diagnosis_report(configs))


if __name__ == "__main__":
    main()

四、IPsec VPN 排障速查表

常见故障与解决方案:

现象 可能原因 解决方案 Phase 1 失败 IKE 参数不匹配 核对算法/认证 Phase 2 失败 ACL 不匹配/PFS 不一致 核对两端 ACL UDP 500 不通 防火墙未放通 放通 UDP 500 UDP 4500 不通 NAT-T 问题 启用 NAT-T SA 建立后立即断开 DPD 问题/Hold 时间 配置 DPD 间歇性断开 NAT 设备老化表项 启用 NAT-T 隧道 UP 但业务不通 路由问题/ACL 不精确 检查路由 加密性能差 算法强度过高/DH 组大 权衡安全与性能 多分支同时断开 总部配置变更 统一变更流程


五、IPsec VPN 配置最佳实践

生产环境推荐配置:

IKE Phase 1(主模式):

IKE 版本: IKEv2(优于 IKEv1) 加密算法: AES256 认证算法: SHA256 DH 组: Group 14(2048位) 认证方式: 预共享密钥(PSK) 生存时间: 86400 秒(24小时)

IPsec Phase 2:

协议: ESP(封装安全载荷) 加密算法: AES256 认证算法: SHA256 PFS: DH Group 14 生存时间: 3600 秒(1小时)

增强功能:

NAT-T: 启用(穿越 NAT 设备) DPD: 间隔 10 秒,重试 3 次 Replay Window: 1024 Anti-Replay: 启用


六、总结

IPsec VPN 排障关键要点:

  1. 分层排查
     └─ 先网络(公网连通性)
     └─ 再防火墙(UDP 500/4500 放通)
     └─ 后 IKE(Phase 1 协商)
     └─ 最后 IPsec(Phase 2 协商)

  2. 常见配置遗漏
     └─ 防火墙未放通 IKE 端口
     └─ NAT 策略影响了 IKE 流量
     └─ 未启用 NAT-T
     └─ 未配置 DPD

  3. 两边配置必须一致
     └─ IKE 算法和认证
     └─ 预共享密钥
     └─ 感兴趣流 ACL
     └─ PFS 配置

  4. 变更管理
     └─ 防火墙变更前评估 VPN 影响
     └─ 保持变更清单,通知相关方
     └─ 变更后及时检查 VPN 状态

下篇预告:第345篇《企业无线网络优化与干扰排查实战案例》——以实际Wi-Fi网络为例,讲解无线网络优化和干扰排查的系统化方法。


下篇预告:第345篇《企业无线网络优化与干扰排查实战案例》——以实际Wi-Fi网络为例,讲解无线网络优化和干扰排查的系统化方法。