[ipsec] 特别硬核的ike/ipsec NAT穿越机制分析
〇 前言
这怕是最后一篇关于IKE,IPSEC的文字了,因为不能没完没了。
所以,我一直在想这个标题该叫什么。总的来说可以将其概括为:IKE NAT穿越机制的分析。
但是,同时它也回答了以下问题:
(1)IKE协议交互消息概述。(2)为什么IKE除了端口500还用了端口4500 。(3)IKE MOBIKE是什么。
(4)迷之端口500和迷之端口4500 。(5)IKE/IPsec为什么要将端口500换成端口4500。
(6)ike/ipsec为什么使用了两个端口。
另外,本篇的所有内容与讨论仅局限在IKE V2的定义域内。
好的,开始。
Author: classic_tong
一 IKE消息简述
我也不想简述,但是不述后边的事情说不清楚。而且,如果是最后一篇的话,也希望能够做一个总结。
如果有的选的话,我建议你不要读我的这一小节,而是读RFC7296的第一章 。然后进入第二小节。
首先,约定一下概念,IKE交互的两端分别叫做发起端和响应端。基本的通信模式是,发起端发送一个请求报文,响应端回复一个响应报文。
这两个报文在一起称为一次交互。一个报文里包含这多个报文段,每个报文段都有其特别的功能和特别的报文段类型,用以和彼此区分。
多次IKE交互之后,IKE通信两端将成功(或者失败)建立一个安全的可信信道。这条信道的建立,删除,状态维护便是IKE交互的任务。
信道建立之后通信任务将交由ESP/AH协议完成。ESP消息承载的通信信息,依据信道标识(SPI)在可信信道间穿梭。
深入到协议细节里的话。IKE交互其实建立了两条信道,一条叫IKE SA,一条叫IPSEC SA(child SA)。在这里,我们将SA理解为信道
的等价物。IKE SA负责信道的可信任性,IPSEC SA负责信道机密性。
下面单独讨论IKE SA。
为了得到可信性IKE需要(1)对双方身份进行AUTH(验证)。同时为了完成信道的建立过程还需要(2)帮助IPSEC SA进行秘钥交换。以及
(3)完成自身信道(ike sa)的秘钥交换。(4)其他特性协商。
以上是IKE的要完成的任务,下面基于对以上任务的理解,我们来看一下IKE的主要交互过程。
先来一张感性的截图,进行一下直观的认识:
主要的IKE交互,按照逻辑顺序,有:
1. IKE_SA_INIT (截图中1,2包)
在这个交互里,完成上文提到的功能3),4)。该交互完成之后IKE SA信道便已经成功建立了。
2. IKE_AUTH (截图中3,4包)
在这个交互中,完成上文提到的功能1)。该交互已经是在IKE SA的保护之下进行的了。并完成了对彼此双方信任的建立。
3. CHILD_SA_CREATE (上面的截图中没有,下面的截图中9,10包)
在这个交互中,完成上文提到的功能2)。在此之后便完成了IPSEC SA信道的建立。
从这个时刻开始,便可以开始进行ESP消息(截图中7,8包,因为解密了,他们带有ESP头)的通信了。但是在实际应用中,在2完成之后,ESP消息交互便已经开始了,是暂时使用的IKE SA的秘钥。
在3完成之后,ESP会切换使用新的秘钥。REKEY也就是秘钥的更新,也是这样的一个过程,使用CHILD_SA_CREATE交互来进行秘钥更新。
4 INFORMATION (截图9,10包)
信道的拆除,探活等其他housekeeping(家务活)任务,都使用该消息完成。
简述到此为止,更多内容可以深入的读上边引用的RFC。下一小节将进入主题NAT穿越。
二 端口
再来一张图。我们惊奇的发现,除了port 500 ,怎么又跑出来一个port 4500 ?尼玛,这到底怎么回事?(为什么上面的图都是500? 这个最后的最后,你就懂了。先剧透一下,上图关了MOBIKE特性)
首先,我详细的描述一下这个现象。 我们前边讨论了,这个IPsec过程分两类报文,一类是IKE报文,一类是ESP报文。然后我们抛开ESP报文不讨论。现在,这个现象是这样的。除了第一次交互(也就是
前两个包)使用500端口之外。之后的所以报文都使用4500端口进行通信。
即使是在发送IKE的rekey或reauth时,也使用4500端口。也就是说500端口,后续的报文序列里再也不会使用了。如图:
接下来,我先说结论,也就是什么情况下什么样的条件会触发这个现象发生。这里边分为两个场景,每个场景有各自的触发条件,如下:
场景A:IKE通信双方至少有一端处于NAT网关的后边。
1. 当通信双方检测到彼此都支持NAT穿越。(当然支持,不然这个场景也没有意义。所以,处于该场景下天然就是触发条件。)
这个时候,在第二次交互开始,通信双方将使用4500端口开始通信。同时ESP包(通常情况下ESP包是IP承载的)会被封包为UDP承载,并使用4500端口。
场景B:IKE通信双方之间没有NAT网关的存在。
1. 通信双方检测到彼此都支持NAT穿越。
2. 通信双方都启用了MOBIKE特性。(原谅我排版不好,你可以先翻到下面去看看mobike是个啥)
场景B下的1,2条件同时满足时,IKE双方将在第二次交互时改用4500端口。因为这两个特性的同时存在,会导致场景B在之后的某个时刻有回落进场景A的可能。
所以,为了防止在突然落入场景A时着急忙慌的切换端口,还不如一开始就切了。(忘记了出处,好像是在 RFC4555 中提到)
所以除了上面的条件,其他情况下,500端口会一直使用。
需要特别说明的是,当使用4500承载的时候,IKE报文头与UDP报文头之间,会插入4个字节的0,用来区分ESP报文和IKE报文。
其他,同样要明确说明的时候,即使在没有出现NAT的情况下,也就是场景B中,4500的报文里同样存在这4个字节的0. 如图留下证据:
图中的两个IP,是我的两个虚拟机,在同一个网段中在host上使用网桥连接。
三 WHY
说了这么多,都是前提。我真正想说的,以及总结了这么多知识并编写了整篇内容的全部动机,其实只是要回答这样一个问题:为什么要换端口?难道不能一直用500端口么?
坦白的说,(经过了大概有怕是4个小时的研究之后)不知道。我收集并总结了如下两个理由,但是,都不能说服我!
理由一和二是整个思考过程,可以跳过。理由三是正解(我差不多都写完了之后,突然无意间找到了理由三,所以,写了不能不写,就索性置灰了)。
理由一:由于NAT设备的某种限制。
因为,rfc7296里有这样一段话,说NAT设备会对4500进行特殊处理,同时也会对500进行特殊处理。
Port 4500 is reserved for UDP-encapsulated ESP and IKE. An IPsec
endpoint that discovers a NAT between it and its correspondent (as
described below) MUST send all subsequent traffic from port 4500,
which NATs should not treat specially (as they might with port 500).
我们知道,500与4500的区别在于500是作为知名端口存在的。总之这里比较含糊。但是作为RFC它给予和我足够多的重视(误导)。
理由二:500与4500代表着不同的抽象含义。
什么意思呢? 就是说作为知名端口(1~1024)和注册端口(1024~49151)每一个都不是随便乱用的。必须有明确的定义和正确的使用方法。
所以,如果用500端口来承载ESP/AH包的话,就含糊了500端口的定义。这样的适合是不好的,所以要用4500来单独承载。
思科如是说:这是一个同样困惑于此的人,也提出了这样的问题给思科之后,思科的回答。我只能说,这听起来好像挺对的,可是存在着无力的逻辑支持。
另外,也是思科,还有,同时一个人特逗,一直耿耿于怀与为什么IKE的源port也必须是500 。以至于因为得不到想要的答案而愤怒。
https://learningnetwork.cisco.com/thread/83219
理由三(精华精华精华)
这个,就是强有力的,无懈可击的,我想要的,答案:https://serverfault.com/questions/937763/ipsec-nat-traversal-on-port-4500
The problem is multiplexing IKE and ESP on the same UDP port. To distinguish between the two protocols one or the other has to be marked somehow (otherwise some potentially error-prone heuristic had to be employed). So continuing on UDP port 500 would have meant to mark the ESP packets as non-IKE packets, in order for the recipient to properly decide whether to process a packet as ESP or hand it to the IKE process. The first two drafts of UDP Encapsulation of IPsec ESP Packets (RFC 3948) actually defined it that way. An all-zero eight byte non-IKE marker in the location where the initiator's IKE SPI is stored in IKE packets was defined as prefix to the actual ESP packet (between UDP header and ESP header). The problem with that was, of course, that there are usually a lot more ESP packets than IKE packets and imposing an overhead of eight bytes (in addition to the UDP header) to every one of them was not ideal. The alternative was to mark the IKE packets, which is what version 02 of the draft defined and eventually ended up in the RFC. An all-zero non-ESP marker of four bytes in the location where the SPI is stored in an ESP packet is inserted between UDP and IKE header. However, that meant port 500 couldn't be used for such packets because all IKE messages (even the first ones) would have to be marked that way, which wouldn't have been backward compatible to IKE/IPsec implementations that didn't support NAT-Traversal. Instead, a separate port is used for UDP-encapsulated ESP and IKE with non-ESP marker. And in order to create a mapping on the NAT before any UDP-encapsulated ESP packets are transmitted (i.e. so inbound traffic can be processed even before any outbound traffic is sent) the switch to port 4500 happens as soon as IKE detects that a NAT is present.
下面,用我的话翻译一下:
首先我们知道,当出现NAT场景时,发起端和响应端直接存在着三种报文。
1. 由UDP4500承载的ESP报文。2. 由UDP4500承载的IKE报文。3.由UDP500承载的IKE报文。
然后我们假设不使用4500端口,而全部使用500端口来承载。之后会发生什么? 首先,NAT设备是没有问题的,对于我们这里讨论或假设的任何场景。
它都可以处理,而且NAT设备也不关心500是不是知名端口,也不对其进行特殊处理。
好,然后,这三种报文都由UDP 500端口来承载。这个时候操作系统收到了udp 500的包的时候是没有办法区分出它到底是IKE还是ESP的。
于是,我们面临一个选择。
A:让操作系统首先进入IKE报文的处理流程,然后为ESP报文加一个特殊的MARK,从而进行区分,识别到ESP报文。
B:让操作系统首先进入ESP报文的处理流程,然后为IKE报文加一个特殊的MARK,从而进行区分,识别到IKE报文。
最终,这个选择里,RFC们选择了B。理由是ESP报文的数量远远多余IKE报文。在每一个包上加mark(也就是四个字节的0)作为一种资源消耗。两种陷害择其轻,自然便选择了IKE。
可是,这依然不能解释,为什么要用两个端口来做。我们可以在最开始的两个包里,便加上这个mark。这样的话所有包都使用500端口也是没有问题的。
然后,并不行。因为为了向前兼容,包格式是不能随便改的。所以只能让带mark的ike报文用新的端口,也就是udp 4500,从而将一开始我们提到的三种报文区分开来。
另外。还能再引申出一个新的问题:为什么不能保持ike的包继续沿用500端口,而只是将UDP封装的esp放在4500端口上?
这样便不需要修改ike的格式(添加四个字节的0)了。
这是因为NAT设备中的端口map关系是需要长期保持的,也就是首选需要NAT内的包使用4500端口触发NAT设备建立映射关系,这样NAT外的设备才能够将ESP包发进来。
设想,如果还是使用500的IKE报文的话。如果NAT内的设备不主动发送ESP包,NAT设备的map表就建立不起来。外边的ESP包也就无法发送回来。
另外,NAT后的信道需要一个NAT-keepalive包来长期保活。有NAT内的一端发送,从而保证NAT设备中的map不会超时。如下图:
四 MOBIKE
虽然解了惑。但是挖了的坑不能不填。MOBIKE在这里:https://tools.ietf.org/html/rfc4555
MOBIKE不是摩拜单车。MOBIKE是 mobile ike。是mobility and multihoming ike。
就是IKE支持,发起端的网络移动,也就是IP变化。以及响应端的多个IP Interface切换,其实也是IP变化。
他们并不是在第一次交互的时候,就协商好了大家都支不支持,而是由发起端根据是否,是否支持NAT,是否MOBIKE等几个条件来决定是发给500还是发给4500
然后,将这个mobike消息段放在第二次交互中传输。(我猜这样设计的目的是为了安全考虑?)如下图:
我看了第三个包的几种情况。包括是否在NAT后,是否支持NAT,是否设置了MOBIKE等。这个message段是否存在都有着不同的情况。
这里就不再进行扩展做详细研究了。因为它并不影响本文所要讨论的所有结论。
不过有一点格外要说的是,它会改变SA的IP!我们回到xfrm与strongswan交互的层面上,再看这个问题。他会导致一个什么样的消息下发呢?
以及xfrm如何兼容,如何做到这个场景下的SA管理呢? 这个话题,有点大。需要作为独立内容进行分析,不在此扩展了。
不过我们还是来撇一下这个交互吧,rfc里的一个示意图:(注意看其中的UPDATE_SA_ADDRESSES部分,我揣测它会触发一个SA UPDATE消息?)
五 NAT穿越协商
本小节讲:通信两端如何知道对方和自己是不是在NAT之后。这里边两方是独自得知的,而不是相互告知。一方要独自回答两个问题,
1. 对面在不在NAT后,2,我在不在NAT后。
再讲这个方法之前,有一个前提,就是在建立连接前每一端都需要被配置一对local IP和remote IP的已知条件。这一对IP就是在该点它所能直接访问(直接到达)的那个两个IP。
所以这个探测方法就是,在第一次交互的第一个包中。发起方将上边提到的配置的两个IP都在payload里发给对方。然后,对方会得到4个IP。两个是报文里边的,另两个是承载
这个报文的IP头里的。所以,只要一对比,响应端就回答了上边那两个问题。反方向机制与过程完全相同,在第一次交互的第二个包里进行。
只不过,意思虽然是这个意思,但是在RFC中规定的实现上,略有区别。payload里存的不是IP而是散列值。收到散列值的一方只需要同样对IP头里的IP做散列,然后进行比较是否一至,就可以判断了。这样即达到了目的,也隐藏了对方的真实IP。
这两个报文段类型的名称是:NAT_DETECTION_SOURCE_IP and NAT_DETECTION_DESTINATION_IP
计算散列的具体方法是: SHA1(SPI + SPI + IP addr + Port number)
详见:https://tools.ietf.org/html/rfc7296#section-2.23
如示例:
六 报文样式
为了理解直观,总结了几种报文的结构,如下图:
其中,需要注意的是,传输模式下TCP报文头中的checksum是错的。因为它保存在加密报文中,所以无法被NAT网关设备修正。这也是为什么
IKE必须关心NAT穿越,而不能无视它的原因之一。
当然,另一个原因是非TCP/UDP承载的报文,会被NAPT设备丢掉?(i dont know..)