当前位置: 首页 > Linux

IPsec和NATTraversal(NAT-T)

时间:2023-04-06 04:50:29 Linux

背景IPsec在两个通信实体之间建立安全的数据传输通道,但它与广泛存在于网络中的NAT设备(和PAT)具有内在的不兼容(incompatible)。我们以一条TCP报文为例,看看这种不兼容在不同的IPsec模式(Transport和Tunnel)和协议(AH和ESP)下是如何产生的。我们先来看一下Transport模式下的AH协议。由于它的认证范围是整个IP包,如果两个IPsec之间有NAT设备,包的IPHeader中的地址被修改,接收方的认证就会失败。对于ESP协议,Authenticate返回不包含IPHeader,所以接收方的Authenticate会通过,但是如果中间NAT设备修改了IPHeader中的地址,理论上后续的TCPchecksum也会相应修改,但是这部分由于ESP协议是加密的,NAT设备没有办法修改,所以接收端收到TCP时会出现checksum校验失败。查看AH协议的Tunnel模式,Tunnel模式和Transport模式没有区别。Authenticate范围包括外层IPHeader,所以也会导致接收方无法Authenticate。对于ESP协议,与Transport模式的区别在于它通过了??NAT设备。内部IPHeader不会改变,所以TCPchecksum不会改变,接收方不会通过checksum验证。从这个角度来看,ESP-Tunnel似乎是NAT设备环境下唯一可行的协议模式组合。但即使是这种组合也有缺点:它只能支持一对一的NAT(NAT设备后面只有一台内网主机)。在很多组网中,通常使用一个NAT设备作为网关,其背后可能有很多主机。这时候,地址翻译还不够,还需要端口翻译。显然,NAT设备对ESP-Tunnel报文无能为力,因为TCP部分已经加密,没有端口字段。因此,IPsec需要想办法绕过NAT设备的影响,即进行NAT穿越(NAT-Tranversal)。UDP-EncapsulateIPsec采用的方法是在ESPHeader之前加一个UDPHeader。此方法适用于ESP-Transport和ESP-Tunnel两种模式。下图显示了ESP-Transport下的UDP-Encapsulate过程。UDP标头有一个端口字段。有了端口,NAT设备就可以进行端口转换。RFC3948规定UDPHeader中的端口要使用与IKE协商时使用的相同的端口号。此端口号在RFC3947中指定为4500。在下面的拓扑中,NAT设备后面有两台内网主机,它们都与Server建立了IPsec连接。主机1和主机2发送的IPsec数据包带有UDP标头。NAT网关替换数据包的源IP和源端口。还有一个问题,对于ESP-Transport模式,如何解决内层TCP报文的checksum校验问题?要知道,经过NAT设备后,报文的IP地址发生了变化,必然导致接收端验证失败。IPsec采用的方法是在IKE协商时将自己的原始IP地址信息发送给对端,以便Server在解密TCP报文后,根据该信息修改校验和NAT-T。以上UDP-Encapsulate只有在IKE时协商完成后才能使用,完成NAT-T。在IKE的第一阶段,双方检测到双方都支持NAT-T。双方检测到报文传输路径上有NAT设备。在IKE的第2阶段,双方协商采用NAT-T封装方式,UDP-Encapsulated-Tunnel或UDP-Encapsulated-Transport(UDP-Encapsulated-Transport)方式将自己的原始IP地址发送给对方,使对方一方可以相应地修改后续TCP数据包的校验和。在T协商期间,Alice和Carol运行Strongswan,Moon作为NAT设备。将IPsec配置为传输模式,并使用IKEv1进行协商和检测。支持NAT-TIPsec的两端会在PHASE1消息1和消息2中交换vendorIDpayload来通知对方他们支持NAT。内容就是字符串“rfc3947”检测IKEPHASE1的消息3和消息4中是否有NAT,通信的双方会交换自己和对方眼中的IP和Port的哈希值。如果中间有NAT设备,则该值必须与报文本身的IP相同。与Port计算的值不一致。将端口从500更改为4500。IKEPHASE1的前4条消息均使用Sport=Dport=500进行通信。但是当检测到NAT设备存在时,作为Initiator的Alice需要在消息5中将端口切换为Sport=Dport=4500,而作为Responder的Carol收到后如果解密成功也会使用新的4500端口该消息之后,后续的IKEPHASE2和业务流量将使用端口4500进行UDP-Encapsulate。为了和业务流量区分开来,IKE阶段的流量后面跟着一个全0的32位Non-ESPMarker(业务流量这个地方用非0的SPI填充)。内核是使用xfrm框架实现的。IPsec数据包收发功能。一般情况下,IP根据协议字段划分IPsec报文和TCPUDP报文。NAT-T场景下,IPsec对报文进行UDP-Encapsulate,接收端看到的是UDP报文,调用udp_rcv()接收报文。那么此时如何进入xfrm框架呢?答案是:Strongswan设置UDP套接字UDP_ENCAP选项,内核绑定一个回调函数xfrm4_udp_encap_rcv()intudp_lib_setsockopt(structsock*sk,intlevel,intoptname,char__user*optval,unsignedintoptlen,int(*push_pending_frames)(structsock*)){//代码省略switch(optname){caseUDP_ENCAP:switch(val){case0:caseUDP_ENCAP_ESPINUDP:caseUDP_ENCAP_ESPINUDP_NON_IKE:up->encap_rcv=xfrm4_udp_encap_encap_rcvt;code//在udp_rcv()的接收过程中,最终会调用回调函数REFRFC3947NegotiationofNAT-TraversalinIKERFC3948UDPEncapsulationofIPsecESPPackets