问题描述
默认情况下,IPsec 传输数据时外层 IP 头部之上为 ESP header 或者 AH header,不管是哪种封装,在传输路径中存在 NAT 设备时都会遇到问题;
在穿越时,AH 的行为
IPSec <---(AH)---> Router (with NAT) <------> Router
针对 Tunnel 和 Transport 模式,最外层的 IP Address 都会参与 AH 的校验,这样带来的问题便是:当 NAT Traversal 时,SRC IP Address 发生变化,而 Auththtication Data 还是原始 Header 的计算结果,当对端收到该数据包时,校验将失败;
所以,针对 AH 协议,不管哪种模式,都无法进行 NAT Traversal 的;
在穿越时,ESP 的行为
IPSec <---(AH)---> Router (with NAT) <------> Router
鉴于 NAT Traversal 仅修改 IP-ADDR,而 ESP 不会对最外层 IP-ADDR 进行校验,所以 NAT 不会导致 ESP 校验失败。
传输模式,会导致传输层 checksum 字段校验失败:
1)在 TCP 中,TCP.Checksum 的伪首部校验会包含 IP Header 的 SRC IP Address 与 DST IP Address。当 NAT Travseral 时,NAT 修改其中的 Checksum 参数。
2)但是 ESP 仅加密四层数据,导致 NAT 无法修改 Checksum,进而导致对端 TCP 校验失败;
隧道模式,将原始的 IP Header 直接封装到 ESP 之中,即使经过 NAT 也不会修改原始地址,而原始校验和依旧有效。所以,隧道模式 + ESP 能够进行 NAT 穿越
但是 ESP 对载荷加密而引发的问题是:ESP 会加密原始数据包传输层数据,进导致端口号不可见,且 ESP 为传输层协议,所以无法支持 NAPT 特性。进而导致仅能使用一对一的 NAT 转换;
解决方案
所以,为了解决该问题,提出 IPSec 的 NAT Traversal 技术
为解决该问题,必须在建立 IPsec 隧道的两个网关上开启 NAT 穿越功能(NAT Traversal);
NAT Traversal,该技术将为 IP Header 与 ESP Header 间增加 UDP(Port 4500) Header 以允许使用 NAPT 特性;
原始报文:| IP Header | ESP | TCP | Payload | 穿越报文:| IP Header | UDP | ESP | TCP | Payload |
推荐配置:Name 验证方式 + Pre-sharekey + 子策略 / 策略模板;
Q:当 NAT 存在时,IPSec 必须使用野蛮模式?
A:鉴于经过 NAT 而导致 IP-ADDR 是变化的,所以无法使用 IP-ADDR 来标识身份,而导致无法使用主模式(Main Mode 不支持以 Peer Name 的方式进行身份表示),只能使用野蛮模式。其实也能使用主模式,即使用经过 NAT 地址的地址作为身份表示,但是这将降低灵活性,所以很少使用该方式;
原理简述
开启 NAT 穿越之后,当检测到(IKE 协商过程中进行检测)两台网关中间存在 NAT 设备,ESP 报文会被封装在一个 UDP 头部中,源目端口号 4500,以此支持经过 NAT 设备;
交互过程
当开启 NAT 穿越时,IKEv1 协商第一阶段的前两个消息会发送标识 NAT 穿越(NAT Traversal,简称 NAT-T)能力的 Vendor ID 载荷(主模式和野蛮模式都是)。用于检查通信双方是否支持 NAT-T,当双方都在各自的消息中包含了该载荷时,才会进行相关的 NAT-T 协商;
主模式消息 3 和消息 4(野蛮模式消息 2 和消息 3)中发送 NAT-D(NAT Discovery)载荷。NAT-D 载荷用于探测两个要建立 IPsec 隧道的网关之间是否存在 NAT 网关以及 NAT 网关的位置。通过协商双方向对端发送源和目的的 IP 地址与端口的 Hash 值,就可以检测到地址和端口在传输过程中是否发生变化。如果协商双方计算出来的 Hash 值与它收到的 Hash 值一样,则表示它们之间没有 NAT。否则,说明传输过程中对 IP 或端口进行了 NAT 转换;
当发现 NAT 网关后,后续 ISAKMP 消息(主模式从消息 5、野蛮模式从消息 3 开始)的端口号转换为 4500;
当检测到存在 NAT 设备之后,ISAKMP 会变化使用的 UDP 端口号,从源目端口号 500 变为 4500;
网关 2 收到报文 3,通过 IP 头部中的源 IP(此时已经为 Y)、源端口(此时非 500)计算 remote hash 值,此时得出来的值并不是 A,从而得知中间存在 NAT 设备;
第一阶段、穿越能力协商
在 IKE Phase 1 中,通过 Vender ID 来确定双方是否支持 NAT Traversal 特性;
第二阶段、检测 NAT 存在
在 IKE Phase 1 中,通过 NAT-D 载荷来检测是否存在 NAT 设备;
这两个 HASH 分别是(源地址:源端口)和(目的地址:目端口)的哈希值,如果接收到发现 HASH 不匹配,则认为存在 NAT 设备,并能通过与之不匹配的 HASH 值检测到 NAT 设备的位置;
Local hash:本地 IP + 端口号 500(默认值)
Remote hash:对端 IP + 端口号 500(默认值)
第三阶段、检测端口可用性
在 IKE Phase 1 中,检测 UDP 4500 端口是否可用;
第四阶段、穿越启用协商
在 IKE Phase 2 的 SA 载荷中,协商是否使用 NAT Traversal 特性;
使用 UDP 封装 IPSec ESP 报文穿越 NAT(其实,第五个和第六个报文已经开始使用 UDP 封装)
后续,封装 ESP 报文端口号与 IKE 所用端口号一致,都为 4500 端口(为了区分两类报文:如果是 ESP 报文,SPI 不能为 0;如果为 IKE 报文,在 UDP 报文,存在 No ESP Mark 字段,全部为 0(四个字节););
在数据发送时,会话保活
网关 1 处在 SNAT(NAPT)设备之后,此时只能网关 1 主动发起流量访问,网关 2 并无法主动发起流量访问,或者当 NAT 设备上的 NAT 转换表项存在时,网关 2 可以发起对网关 1 的主动访问,为了保证网关 1、网关 2 都可以任意发起流量访问,需要存在一种机制保证 SNAT 设备的 NAT 会话不会超时;
为保证 NAT 设备会话表项不老化,NAT 设备内侧设备(网关 1)会定期发送 NAT Keepalive 报文,维持 NAT 会话的存活,当检测到中间路径存在 NAT 设备之后,设备缺省 20s 发送一次 NAT Keepalive 报文;
NAT Keepalive 报文格式非常简单,在 UDP 头部之后为两个十六进制 F,用于刷新 NAT 设备会话表项;
应用场景
分部主动发起协商(分部地址未知)
该场景中,NAT 设备位于分部网络之外,分部网关 1 出接口的私网 IP 地址 X,经过 NAT 设备转换后变为公网 IP 地址 Y。由于总部无从获知经过 NAT 设备转换后的分部公网 IP 地址,也就无法在总部网关 1 上明确指定对端的公网地址。因此,总部网关 2 必须使用模板方式来配置 IPsec,同时总部和分布的网关上都要开启 NAT 穿越功能;
总部既然使用了模板方式,那就无法主动访问分部,只能由分部主动向总部发起 ISAKMP 协商;
分部主动发起协商(分部地址已知)
该场景中,NAT 设备位于分部网络之外,分部网关 1 出接口的私网 IP 地址 X,经过 NAT 设备转换后变为公网 IP 地址 Y。NAT 转换设备为分部自己管理设备,并且公网 IP 地址固定,此时转换后的公网地址可知,此时总部可以使用模板方式或者手动指定对等体的方式配置 IPsec;
此时由于 NAT 设备只进行源地址转换,所以依旧只能由分部主动发起 ISAKMP 协商;
分部通过 NAT Server 映射端口
该场景中,NAT 设备为分部管理设备,提供 NAT Server 功能,映射网关的接口地址(UDP 500、UDP 4500),总部上使用手动指定对等体的方式配置 IPsec,此时可以实现总部主动发起 ISAKMP 协商以及流量访问。
参考文献
https://www.synopsys.com/dw/dwtb/ethernet_mac/ethernet_mac.html
networking – Router/NAT and IP/TCP header checksum – Super User