IPsec作为一种重要的安全技术得到越来越广泛的应用,但是客户网络边缘大量使用的NAT地址转换操作可能影响到IPsec的正常操作。目前,NAT和IPsec之间存在的不兼容性问题主要可以分为以下三类:
l IP地址和端口不匹配的问题
l IPsec不能验证NAT报文的问题
l NAT超时影响IPsec的问题
在IKE野蛮模式的基础上实现NAT穿越,很好地解决了此问题。
为了使IKE支持目前广泛应用的通过ADSL及拨号方式构建VPN的方案中的特殊情况――即局端设备的IP地址为固定分配的,用户端设备的IP地址为动态获取的情况,在IKE阶段的协商模式中增加了IKE野蛮模式,它可以选择根据协商发起端的IP地址或者ID来查找对应的身份验证字,并最终完成协商。IKE野蛮模式相对于主模式来说更加灵活,能够支持协商发起端为动态IP地址的情况。
在IPsec/IKE组建的VPN隧道中,若存在NAT网关设备,且NAT网关设备对VPN业务数据流进行了NAT转换的话,则必须配置IPsec/IKE的NAT穿越功能。该功能删去了IKE协商过程中对UDP端口号的验证过程,同时实现了对VPN隧道中NAT网关设备的发现功能,即如果发现NAT网关设备,则将在之后的IPsec数据传输中使用UDP封装(即将IPsec报文封装到IKE协商所使用的UDP连接隧道里)的方法,避免了NAT网关对IPsec报文进行篡改(NAT网关设备将只能够修改最外层的IP和UDP报文头,对UDP报文封装的IPsec报文将不作修改),从而保证了IPsec报文的完整性(IPsec数据加密解密验证过程中要求报文原封不动地被传送到接收端)。目前仅在IKE野蛮模式下支持NAT穿越,主模式下不支持。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------另一篇:
1.从IPsec的角度上说,IPsec要保证数据的安全,因此它会加密和校验数据。
2.从NAT的观点来看,为了完成地址转换,势必会修改IP地址。
2. IKE协商使用UDP封装
+---------------+---------------+---------------+---------------+
| Next Payload | RESERVED | Payload length |
+---------------+---------------+---------------+---------------+
~ HASH of the address and port ~
+---------------+---------------+---------------+---------------+
HASH值的计算方法如下,具体HASH是根据协商来确定的:
------------ ------------
UDP(500,500) HDR, SA, VID -->
<-- UDP(500,X) HDR, SA, VID
UDP(500,500) HDR, KE, Ni,
NAT-D, NAT-D -->
<-- UDP(500,X) HDR, KE, Nr,
NAT-D, NAT-D
UDP(4500,4500) HDR*#, IDii,
[CERT, ]SIG_I -->
<-- UDP(4500,Y) HDR*#, IDir,
[ CERT, ], SIG_R
2.2 UDP封装协商
UDP-Encapsulated-Transport 4
+---------------+---------------+---------------+---------------+
| Next Payload | RESERVED | Payload length |
+---------------+---------------+---------------+---------------+
| ID Type | RESERVED | RESERVED |
+---------------+---------------+---------------+---------------+
| IPv4 (4 octets) or IPv6 address (16 octets) |
+---------------+---------------+---------------+---------------+
值得注意的是只是在传输模式下需要传NAT-OA载荷,但通道模式下就没必要传了,具体原因看下节UDP封装方法后再说明。
交换过程如下:
------------ ------------
HDR*, HASH(1), SA, Ni, [, KE]
[, IDci, IDcr ]
[, NAT-OAi, NAT-OAr] -->
<-- HDR*, HASH(2), SA, Nr, [, KE]
[, IDci, IDcr ]
[, NAT-OAi, NAT-OAr]
HDR*, HASH(3) -->
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ESP header [RFC4303] |
~ ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
----------------------------
IPv4 |orig IP hdr | | |
|(any options)| TCP | Data |
----------------------------
-------------------------------------------------------
IPv4 |orig IP hdr | UDP | ESP | | | ESP | ESP|
|(any options)| Hdr | Hdr | TCP | Data | Trailer |Auth|
-------------------------------------------------------
|<----- encrypted ---->|
|<------ authenticated ----->|
数据包经过NAT设备后,只修改外部IP头和UDP头中的数据,TCP头中的数据是不可能修改的(实际NAT设备也根本看不到TCP头数据,因为是被ESP加密了的)。经过ESP/UDP协议解封装处理,到达应用层时的数据包剩下修改后的外部IP头和原始TCP头,因此TCP头中的校验和必须和修改后的IP头中的地址匹配,否则在应用层看来就是错误的。因此IKE时必须交换NAT-OA载荷,使ESP/UDP处理层知道如何修改TCP校验和,而对于上层的UDP协议,可以简单的将校验和置0即可。
----------------------------
IPv4 |orig IP hdr | | |
|(any options)| TCP | Data |
----------------------------
--------------------------------------------------------------
IPv4 |new h.| UDP | ESP |orig IP hdr | | | ESP | ESP|
|(opts)| Hdr | Hdr |(any options)| TCP | Data | Trailer |Auth|
--------------------------------------------------------------
|<------------ encrypted ----------->|
|<------------- authenticated ------------>|
内部IP头也是ESP载荷的一部分,因此TCP校验和已经是根据内部IP头计算的了,因此在IKE时不用交换NAT-OA载荷,解封处理只需要按顺序依次解开UDP和ESP就能还原原始数据包。
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Non-ESP Marker |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IKE header [RFC4306] |
~ ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xFF |
+-+-+-+-+-+-+-+-+
4. 冲突
| |-------------|----\
+----+ / \ \
A NAT 1 \
\
10.1.2.3 \
+----+ \ / \ +----+ +----+
| |-------------|----------+------| |----------| |
+----+ / \ +----+ +----+
B NAT 2 远程VPN网关 远程服务器
10.1.2.3
在传输模式下更容易发生问题,对于下面的拓扑结构:
+----+
| |
+----+ \
A \
10.1.2.3 \
\
+----+ \ / +----+
| |-----+-----------------| |
+----+ / \ +----+
B NAT 服务器
10.1.2.4 /
/
/
+----+ /
| |/
+----+
C
10.1.2.5
1. 对于IPsec-ESP来说,NAT设备不能找到要做端口转换的port和src IP address的位置(因为它已经被加密了)
2.对外IPsec-AH协议,NAT设备虽然可以看到port和Src IP and Dst IP address,但不可以修改,如果一修改整个IPsec数据包的完整性验证就会失败。IPsec 数据包就会被丢弃。
二 IPsec和NAT和平共处的解决方法:NAT-T
在 IPsec第一阶段IKE SA协商过程中,两端支持NAT-T的VPN 设备会在IPSec 协商路径上检测是否有NAT设备,
1. 如果没有NAT设备,IPSec数据包正常发送,接着进入IKE第二阶段
2. 如果监测到NAT设备,就给要发送出去的IPSec数据包再添加一层UDP封装。可以解决认证检查失败的问题。NAT设备将其作为 UDP 封包处理,更改UDP 包头中的源端口,不修改 AH 或 ESP 中的 SPI 包头。对端的VPN设备将剥开UDP 层并处理 IPSec 封包,这样处理就会通过认证检查,因为对认证过的内容并没有做任何更改。
1.启用NAT-T之后,也只要两端的VPN Gateway之间存在NAT设备时才会激活。
2.要使用NAT-T功能,两端的VPN Peer都必须支持。
added connection description "shiyantoxili/1x1"
added connection description "shiyantoxili/1x2"
initiating all conns with alias='shiyantoxili'
"shiyantoxili/1x2" #1538: initiating Aggressive Mode #1538, connection "shiyantoxili/1x2"
"shiyantoxili/1x2" #1538: received Vendor ID payload [Dead Peer Detection]
"shiyantoxili/1x2" #1538: received Vendor ID payload [RFC 3947] method set to=115
"shiyantoxili/1x2" #1538: Aggressive mode peer ID is ID_FQDN: '@xili'
"shiyantoxili/1x2" #1538: NAT-Traversal: Result using draft-ietf-ipsec-nat-t-ike (MacOS X): both are NATed
"shiyantoxili/1x2" #1538: transition from state STATE_AGGR_I1 to state STATE_AGGR_I2
"shiyantoxili/1x2" #1538: STATE_AGGR_I2: sent AI2, ISAKMP SA established {auth=OAKLEY_PRESHARED_KEY cipher=oakley_3des_cbc_192 prf=oakley_sha group=modp1024}
"shiyantoxili/1x2" #1538: Dead Peer Detection (RFC 3706): enabled
"shiyantoxili/1x1" #1539: initiating Quick Mode PSK+ENCRYPT+TUNNEL+PFS+UP+AGGRESSIVE+IKEv2ALLOW+SAREFTRACK {using isakmp#1538 msgid:2954fd80 proposal=3DES(3)_192-SHA1(2)_160 pfsgroup=OAKLEY_GROUP_MODP1024}
"shiyantoxili/1x2" #1540: initiating Quick Mode PSK+ENCRYPT+TUNNEL+PFS+UP+AGGRESSIVE+IKEv2ALLOW+SAREFTRACK {using isakmp#1538 msgid:236ba11e proposal=3DES(3)_192-SHA1(2)_160 pfsgroup=OAKLEY_GROUP_MODP1024}
"shiyantoxili/1x1" #1539: Dead Peer Detection (RFC 3706): enabled
"shiyantoxili/1x1" #1539: transition from state STATE_QUICK_I1 to state STATE_QUICK_I2
"shiyantoxili/1x1" #1539: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode {ESP=>0xc417d95b <0x3f4913c4 xfrm=3DES_0-HMAC_SHA1 NATOA=none NATD=113.91.86.106:4500 DPD=enabled}
"shiyantoxili/1x2" #1540: Dead Peer Detection (RFC 3706): enabled
"shiyantoxili/1x2" #1540: transition from state STATE_QUICK_I1 to state STATE_QUICK_I2
"shiyantoxili/1x2" #1540: STATE_QUICK_I2: sent QI2, IPsec SA established tunnel mode {ESP=>0xc417d95c <0x3f4913c5 xfrm=3DES_0-HMAC_SHA1 NATOA=none NATD=113.91.86.106:4500 DPD=enabled}
接收端日志:
packet from 113.104.226.246:500: received Vendor ID payload [Dead Peer Detection]
packet from 113.104.226.246:500: received Vendor ID payload [RFC 3947] method set to=115
packet from 113.104.226.246:500: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-03] meth=108, but already using method 115
packet from 113.104.226.246:500: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-02_n] meth=106, but already using method 115
packet from 113.104.226.246:500: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-02] meth=107, but already using method 115
packet from 113.104.226.246:500: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-00]
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: Aggressive mode peer ID is ID_FQDN: '@shiyan'
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: responding to Aggressive Mode, state #404, connection "xilitoshiyan/1x1" from 113.104.226.246
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: enabling possible NAT-traversal with method RFC 3947 (NAT-Traversal)
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: transition from state STATE_AGGR_R0 to state STATE_AGGR_R1
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: STATE_AGGR_R1: sent AR1, expecting AI2
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: NAT-Traversal: Result using draft-ietf-ipsec-nat-t-ike (MacOS X): both are NATed
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: transition from state STATE_AGGR_R1 to state STATE_AGGR_R2
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: new NAT mapping for #404, was 113.104.226.246:500, now 113.104.226.246:4500
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: STATE_AGGR_R2: ISAKMP SA established {auth=OAKLEY_PRESHARED_KEY cipher=oakley_3des_cbc_192 prf=oakley_sha group=modp1024}
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: the peer proposed: 192.168.3.0/24:0/0 -> 192.168.1.0/24:0/0
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: responding to Quick Mode proposal {msgid:2954fd80}
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: us: 192.168.3.0/24===192.168.0.188[@xili]
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: them: 113.104.226.246<0.0.0.0>[@shiyan]===192.168.1.0/24
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: keeping refhim=4294901761 during rekey
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: transition from state STATE_QUICK_R0 to state STATE_QUICK_R1
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: STATE_QUICK_R1: sent QR1, inbound IPsec SA installed, expecting QI2
"xilitoshiyan/1x1"[1] 113.104.226.246 #404: the peer proposed: 192.168.0.0/24:0/0 -> 192.168.1.0/24:0/0
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: responding to Quick Mode proposal {msgid:236ba11e}
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: us: 192.168.0.0/24===192.168.0.188[@xili]
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: them: 113.104.226.246<0.0.0.0>[@shiyan]===192.168.1.0/24
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: keeping refhim=4294901761 during rekey
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: transition from state STATE_QUICK_R0 to state STATE_QUICK_R1
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: STATE_QUICK_R1: sent QR1, inbound IPsec SA installed, expecting QI2
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: transition from state STATE_QUICK_R1 to state STATE_QUICK_R2
"xilitoshiyan/1x1"[1] 113.104.226.246 #405: STATE_QUICK_R2: IPsec SA established tunnel mode {ESP=>0x3f4913c4 <0xc417d95b xfrm=3DES_0-HMAC_SHA1 NATOA=none NATD=113.104.226.246:4500 DPD=none}
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: transition from state STATE_QUICK_R1 to state STATE_QUICK_R2
"xilitoshiyan/2x1"[1] 113.104.226.246 #406: STATE_QUICK_R2: IPsec SA established tunnel mode {ESP=>0x3f4913c5 <0xc417d95c xfrm=3DES_0-HMAC_SHA1 NATOA=none NATD=113.104.226.246:4500 DPD=none}
附:openswan代码中流程文档
The document describes the steps that a packet goes through when it is
received by pluto. This is not a state machine, but rather a call graph,
in general each run through the process causes a single state change.
* read_packet()
The packet is received from the network and the origin and destination
address and the ports of the packet are recorded. Based upon the destination
port, a particular interface definition is chosen.
The packet is stored into an object called the "msg_digest"
A single common (statically allocated) msg_digest is used to receive all
packets, if it needs to be saved (not the common case), it is copied.
* process_packet()
process_packet() is the primary function which parses the incoming packet.
In the diagram, this is why all other functions appear to be called from this
function.
* de-marshal payloads (in_struct)
The first step is to take the packet apart. This is done by the in_struct()
routine, which turns the wire format into a structure, found in md->hdr.
* examine isa_xchg
The first step is to look at the exchange type. Many exchange types are not
supported. In general each type will cause a new state to be created when
the msgid is different than a different code was done.
* find/create state object
Each type will search for a state object that matches the set of cookies, and
the message id. If no state object is found, a new one may be created.
If the state is not found by the message ID, then we look for state with a
zero message ID. If that is found, then the state is adjusted to now be for
this message ID.
* determine valid transitions
Once we have a state object, it can determined what are valid transitions
from this state to another state. The selection is typically based upon what
payloads are present in the message. The transition microcode has a bit for
each payload type, and based upon this we determine if there would be a valid
state transition.
This microcode also then indicates things such as whether or not the message
should be encrypted, and whether or not additional options payloads may appear.
* verify state is not suspended
The state may be suspended. This will occur if there is computation (such as
a Diffie-Hellman exponentiation) occuring or a network lookup is occuring
(DNS). If so, the packet will be dropped. Likely, it is a retransmission
anyway.
Retransmissions are also detected --- if we have already replied to this
message, then we will have saved the outgoing packet, and it is simply
resent.
* decrypt packet if appropriate
The message may have been encrypted. The state transition may be valid only
with an encrypted message. These two conditions are compared, and if they
match, then the message is decrypted.
The resulting new data will have new payloads, and these will be
de-marshalled.
* calculate hash if appropriate
Prior to losing track of the newly decrypted message, we calculate
over the plaintext, which may be used later on to authenticate the message.
* enforce ordering of payloads
Some ordering of payloads is mandated, and without this ordering the message
may not make sense. This is then checked.
* state specific func
The state transition microcode ("smc") will have designated a particular
function handle the state transition. The function will be passed a pointer
to the pointer to the message digest, and a pointer to the microcode.
The reason a pointer to a pointer is passed is so that the state specific
function can set the message digest to NULL. It will do this in situations
where it needs to keep a copy of the message for later examination by a
continuation function. Since the pointer will now be NULL, the enclosing
read_packet() function will not free the message digest, and a new one will
be allocated for the next packet.
State specific functions are named for the exchange type, and message number
they expect. For instance, [[quick_inI1_outR1]] is part of a QuickMode (aka
"Phase 2") exchange, and is called by the responder when it receives message
I1 in order to prepare the R1 message
A typical negotiation looks like this:
[[main_outI1]]
------I1----->
[[main_inI1_outR1]]
<-----R1------
[[main_inR1_outI2]]
------I2----->
[[main_inI2_outR2]]
<-----R2------
[[main_inR2_outI3]]
------I3----->
[[main_inI3_outR3]]
<-----R3------
[[main_inR3]]
| PHASE 1 ESTABLISHED
|
V
[[quick_outI1]]
------I1----->
[[quick_inI1_outR1]]
<-----R1------
[[quick_inR1_outI2]]
| ------I2----->
| [[quick_inI2]]
| |
V V
PHASE 2 ESTABLISHED PHASE 2 ESTABLISHED
Details about each state transition is covered in additional pages above.
* complete_state_transition()
The state specific function is expected to return one of the following
returns of type stf_status (State Transition Function Status).
** STF_IGNORE
An ignore value means that this message should not cause any change to the
current stat. No further processing is done.
** STF_INLINE
A return of INLINE is a meta value, and means that the state transition has
already been performed.
** STF_SUSPEND
A return of SUSPEND means that the state transition function could not (yet)
complete the state transition. A continuation function (to be called later)
will likely complete the transition.
** STF_FATAL
A return of FATAL means that something is wrong in the configuration of this
connection pluto, and likely that it will be unable to continue processing.
** STF_INTERNAL_ERROR
An internal error means that a system wide resource is misconfigured, and it
is likely that no connection will succeed.
** STF_FAIL
A simple failure means that the message was not successfully processed. This
could be due to inability to authenticate the message, mismatches in policy,
etc. It may also be due to malicious corruption of the exchange.
** STF_TOO_MUCH_CRYPTO
The message could not be processed at this time because the system is too
busy processing other (more important) messages. The message is dropped, and
retransmission will take care of resending it.
** STF_OK
The message was successfully processed, and the state should be advanced.
The received message is record (in case it is retransmitted), and if this
state requires a response, any response message will then be sent.
*** send_packet()
The send_packet() process actually transmits the reply. It uses the remote
address and port that has been stored in the state structure, since the
NAT-traversal code may have updated these values.
* encrypt packet
The state specific function, if it prepares a reply packet, may need to
encrypt it. This is done in a single function.
* continuation
Many state specific functions require that some work be done: this may
involve one or more DNS or LDAP lookups to retrieve public keys, or may
involve performing lengthy cryptographic operations. In this case, the state
specific function will arrange to have the operation started. A continuation
structure is created when the operation is started, and the state specific
function will return STF_SUSPENDED.
When the asynchronous operation is completed, a continuation function (often
called the _tail function) is called, it is provided with the continuation
structure, and a reply message is fashioned. Typically, the continuation
function will then call complete_state_transition() itself.
http://blog.youkuaiyun.com/jianchaolv/article/details/7903882
http://blog.youkuaiyun.com/jianchaolv/article/details/8454991
https://tools.ietf.org/html/draft-ietf-ipsec-nat-t-ike-03#page-5