在全球IPv4地址愈发匮乏的大背景下,NAT技术应运而生,并且随着时间的推移,这项技术运用的越来越广泛。在实际应用中,NAT大体可以分成EasyIP、PAT、NOPAT、静态NAT和NAT Server几种用法。
NAT技术的原理并不复杂,如图1所示,三个带有内部地址的数据报文到达NAT设备,其中报文1和报文2来自同一个内部地址但有不同的源端口号,报文1和报文3来自不同的内部地址但具有相同的源端口号。通过NAT映射,三个数据报的源IP地址都被转换到同一个外部地址,但每个数据报都被赋予了不同的源端口号,因而仍保留了报文之间的区别。当各报文的回应报文到达时,NAT设备仍能够根据回应报文的目的IP地址和目的端口号来区别该报文应转发到的内部主机。
图1 源地址转换原理图
NAT设备通过建立五元组(源地址、源端口号、协议类型、目的地址、目的端口号)表项为依据进行地址分配和报文过滤。即,对于来自相同源地址和源端口号的报文,若其目的地址和目的端口号不同,通过映射后,相同的源地址和源端口号将被转换为不同的外部地址和端口号,并且NAT设备只允许这些目的地址对应的外部网络的主机才可以通过该转换后的地址和端口来访问这些内部网络的主机。
原理虽然简单,但是在实际应用中还是会碰到各种的问题,比如ICMP报文没有端口号,设备如何进行NAT映射?分片报文中没有四层信息,设备又如何进行NAT映射?本文将以H3C公司SecPath F1000-E设备为例,对NAT的特殊处理进行深入的解析。
首先我们在设备上配置一个PAT方式的NAT转换,一个NOPAT方式的NAT转换,再配置两个NAT Server:
#
nat address-group 3 218.197.70.10 218.197.70.19
nat address-group 13 61.154.70.20 61.154.70.29
#
interface GigabitEthernet0/3
port link-mode route
nat outbound 3001 address-group 13 no-pat
nat outbound 3000 address-group 3
nat server protocol tcp global 218.197.70.20 www inside 192.168.200.2 www
nat server protocol udp global 218.197.70.21 tftp inside 192.168.200.2 tftp
ip address 218.197.70.1 255.255.255.0
#
当我们查看路由表的时候可以看到NAT地址池的地址以及NAT Server的公网地址全部被加入其中。
<SecPath F1000-E>display ip routing-table
Routing Tables: Public
Destinations : 31 Routes : 31
Destination/Mask Proto Pre Cost NextHop Interface
0.0.0.0/0 Static 60 0 162.105.12.1 GE0/0
61.154.70.20/32 Static 1 0 0.0.0.0 NULL0
61.154.70.21/32 Static 1 0 0.0.0.0 NULL0
61.154.70.22/32 Static 1 0 0.0.0.0 NULL0
61.154.70.23/32 Static 1 0 0.0.0.0 NULL0
61.154.70.24/32 Static 1 0 0.0.0.0 NULL0
61.154.70.25/32 Static 1 0 0.0.0.0 NULL0
61.154.70.26/32 Static 1 0 0.0.0.0 NULL0
61.154.70.27/32 Static 1 0 0.0.0.0 NULL0
61.154.70.28/32 Static 1 0 0.0.0.0 NULL0
61.154.70.29/32 Static 1 0 0.0.0.0 NULL0
127.0.0.0/8 Direct 0 0 127.0.0.1 InLoop0
127.0.0.1/32 Direct 0 0 127.0.0.1 InLoop0
162.105.12.0/24 Direct 0 0 162.105.12.211 GE0/0
162.105.12.211/32 Direct 0 0 127.0.0.1 InLoop0
192.168.200.0/24 Direct 0 0 192.168.200.1 GE0/2
192.168.200.1/32 Direct 0 0 127.0.0.1 InLoop0
218.197.70.0/24 Direct 0 0 218.197.70.1 GE0/3
218.197.70.1/32 Direct 0 0 127.0.0.1 InLoop0
218.197.70.10/32 Static 1 0 0.0.0.0 NULL0
218.197.70.11/32 Static 1 0 0.0.0.0 NULL0
218.197.70.12/32 Static 1 0 0.0.0.0 NULL0
218.197.70.13/32 Static 1 0 0.0.0.0 NULL0
218.197.70.14/32 Static 1 0 0.0.0.0 NULL0
218.197.70.15/32 Static 1 0 0.0.0.0 NULL0
218.197.70.16/32 Static 1 0 0.0.0.0 NULL0
218.197.70.17/32 Static 1 0 0.0.0.0 NULL0
218.197.70.18/32 Static 1 0 0.0.0.0 NULL0
218.197.70.19/32 Static 1 0 0.0.0.0 NULL0
218.197.70.20/32 Static 1 0 0.0.0.0 NULL0
218.197.70.21/32 Static 1 0 0.0.0.0 NULL0
如图2所示,从内网来的报文经过NAT转换,到达外网中的目的地,目的主机向NAT转换后的地址回应报文;当报文到达与NAT出接口直连的设备时,这个设备并不知道这个经过转换的公网地址所对应的MAC,此时便会发送ARP请求。
图2 NAT设备的ARP响应
NAT使用的公网地址,包括了被引用的地址池的地址、NAT Server的公网地址和被引用的静态配置的公网地址。这些地址全部会进入地址管理模块进行统一地址管理,并由地址管理模块通知路由管理模块将这些IP地址加入路由表。当外部设备向这些地址发起ARP请求,设备便会将ARP请求送到地址管理模块检查ARP报文的合法性,地址管理发现ARP所请求的IP地址为NAT地址池地址,则通知NAT模块判断是否需要回应ARP,NAT模块会检查ARP所请求的IP地址是否是收到ARP接口下配置的NAT的地址,如果是则通知ARP模块进行ARP应答。
由于有了地址统一管理,与接口不在同一网段的地址池的地址被加入的本地路由表,并且可以有选择的将其引入动态路由协议,通过OSPF或者BGP将其发布出去,简化了组网中其他设备的配置。
双机热备对于防火墙来说是一个必不可少的功能,两台防火墙上的NAT配置也需要完全相同,这样就会出现一个问题:如果两个防火墙分别将两条不同的流映射到相同的公网地址,并且端口也相同的话,势必会造成表项的混乱,所以我们引入了地址池优先级的概念。
在双机热备的环境中,如果地址池被配置为高优先级,在进行端口映射的时候端口取值范围为1024~35000;如果地址池被配置为低优先级,其端口取值范围为35001~65535。这样主备两台防火墙虽然使用相同的NAT地址池中的地址,但是由于地址池的优先级不同,所以就不会出现NAT转换后公网IP和公网端口完全相同的情况了。
地址池优先级只有在双机热备的环境中才有意义,如果是单机环境,高优先级的地址池的端口取值范围就是1024~65535,而低优先级地址池的端口取值范围依旧是35001~65535。
H3C ComwareV5平台为了保证内网的安全性,采用了五元组匹配NAT映射表项,但是ICMP报文没有类似于TCP和UDP报文的端口信息,既要对ICMP的请求报文进行NAT映射,又要确保网络的安全性,只允许合法的ICMP响应报文进入内网,就必须对其进行特殊的处理。
图3 NAT简单组网图
图3是一个最简单的NAT组网图,内网使用192.168.200.0/24的私网地址,外网是218.197.70.0/24的公网地址,而在设备连接外网的接口上我们启用了NAT。我们从内网的PC1去PING外网的PC2是可以成功的,而我们在设备上看到了这样的一个表项:
Initiator:
Source IP/Port : 192.168.200.2/2048
Dest IP/Port : 218.197.70.2/1024
VPN-Instance/VLAN ID/VLL ID:
Responder:
Source IP/Port : 218.197.70.2/0
Dest IP/Port : 218.197.70.12/1036
VPN-Instance/VLAN ID/VLL ID:
Pro: ICMP(1) App: unknown State: ICMP-CLOSED
Start time: 2011-05-28 11:44:35 TTL: 23s
Root Zone(in): Private
Zone(out): Public
Received packet(s)(Init): 4 packet(s) 240 byte(s)
Received packet(s)(Reply): 4 packet(s) 240 byte(s)
既然ICMP报文没有端口信息,那么表项中的端口信息又是从何而来的呢?我们不妨通过对报文的分析找到答案。
图4 内网ICMP请求报文
从内网抓到的ICMP请求报文可以看出TYPE+CODE字段的值是0x0800,而Identifier字段的值是0x0400,这两个值转换成十进制的数值,正好是2048和1024。与发起方的源端口数值和目的端口数值一致。那么我们再看一下内网抓到的ICMP响应报文是否可以与响应方的源端口和目的端口对应。
图5 内网ICMP响应报文
在响应报文中TYPE+CODE字段为0x0000,十进制也是0,这与表项中响应方的源端口相同;但是问题出现在响应方的目的端口,在报文中Identifier字段的值是0x0400,十进制为1024,而表项中的目的端口却为1036,这又是为什么呢?原来Windows系统发出的ICMP报文的Identifier字段全部都为0x0400,当多台内网PC同时PING一个外网PC时,如果设备仅仅对Identifier字段进行简单的运算,极有可能造成多个表项中响应方的参数相同,使得回程报文发送错误。为避免这种情况的发生,设备会在对ICMP请求报文进行IP地址转换的同时,还会选择一个空闲的端口号对报文中的Identifier字段进行变化,以避免上述情况的发生。
图6 外网ICMP请求报文
在图6中我们可以看到转换后的ICMP请求报文的Identifier字段已经变成了0x040c,也就是十进制的1036,这与表项中响应方的目的端口一致,这样的一个五元组就能唯一确定一个PING操作了。
内网PC1试图通过TFTP协议从外网的PC2下载aaa.bin文件,但是PC2并没有开启TFTP服务,这时PC2会向PC1回应ICMP端口不可达的差错报文。如果我们依然按照上一节中的规则来理解ICMP差错报文的转换过程,那就大错特错了。对于源地址转换的NAT来说,外网的报文要想顺利进入内网,就必须五元组匹配设备上的NAT表项,内网访问外网时使用的是UDP协议,而ICMP差错报文是ICMP协议,这一点就不符合要求。但是从图7内网PC1上抓包我们清楚的看到这个ICMP差错报文确确实实的被转发了进来。这其中的奥妙就在于设备对ICMP差错报文的特殊处理。
图7 内网TFTP访问抓包
当PC1访问PC2时,设备上会生成这样一个表项,PC1使用的是UDP协议,源IP和源端口为192.168.200.2/2428,目的IP和目的端口为218.197.70.2/69;设备进行NAT转换后的源IP和源端口为218.197.70.12/1048。
Initiator:
Source IP/Port : 192.168.200.2/2428
Dest IP/Port : 218.197.70.2/69
VPN-Instance/VLAN ID/VLL ID:
Responder:
Source IP/Port : 218.197.70.2/69
Dest IP/Port : 218.197.70.12/1048
VPN-Instance/VLAN ID/VLL ID:
Pro: UDP(17) App: TFTP State: UDP-OPEN
Start time: 2011-05-28 13:17:49 TTL: 119s
Root Zone(in): Private
Zone(out): Public
Received packet(s)(Init): 2 packet(s) 88 byte(s)
Received packet(s)(Reply): 0 packet(s) 0 byte(s)
再让我们来看看PC2回应的ICMP差错报文的结构,如图8和图9所示:
图8 外网ICMP差错报文结构
图9 内网ICMP差错报文结构
比较内网和外网的报文之后答案已经非常清楚了,设备根据ICMP差错报文体中的IP地址和端口号匹配设备上的NAT表,再根据这个NAT表项对报文目的IP,以及报文体中的源IP和源端口进行了转换,然后发送到内网的PC1。
同时设备会根据ICMP差错报文对相应的会话进行加速老化,已达到节省设备资源的目的。刚才老化时间还是120秒的表项在收到ICMP差错报文后迅速将老化时间调整为15秒。会话状态也由UDP-OPEN变为了Accelerate。
Initiator:
Source IP/Port : 192.168.200.2/2428
Dest IP/Port : 218.197.70.2/69
VPN-Instance/VLAN ID/VLL ID:
Responder:
Source IP/Port : 218.197.70.2/69
Dest IP/Port : 218.197.70.12/1048
VPN-Instance/VLAN ID/VLL ID:
Pro: UDP(17) App: TFTP State: Accelerate
Start time: 2011-05-28 13:17:49 TTL: 14s
Root Zone(in): Private
Zone(out): Public
Received packet(s)(Init): 9 packet(s) 403 byte(s)
Received packet(s)(Reply): 0 packet(s) 0 byte(s)
在PAT转换类型的NAT地址转换中,NAT除了对IP地址转换外,还使用到TCP或UDP报文的端口号、ICMP报文的ICMP头中的Identifier字段信息。当一个报文被分成若干片之后,这些信息只有首片报文会携带,后续分片报文依靠报文ID、分片标志位、分片偏移量依次关联到前一个分片。以ICMP报文为例,说明NAT对分片的IP报文进行的处理。在ICMP报文分片后,只有在首片ICMP报文中包含ICMP头的Identifier字段。在首片报文到达NAT设备后,按照正常的转换流程,根据源IP地址和Identifier信息生成转换表项并转发出去。在第二个及后续分片到达后,由于只包含IP地址却没有Identifier信息,可能因此无法进行NAT转换。解决的办法有两种:
1) 先重组,再进行NAT转换,在分片报文到达后,先进缓存,等属于这个IP报文的所有分片到达后进行虚拟分片重组,再进行NAT地址转换。最后将NAT转换完成的IP报文按照顺序发送出去。
2) 在首片到达并转换后,设备记录并保存转换首片使用的IP及Identifier信息,并在后续分片到达后应用同样的转换表项进行转换。
在H3C SecPath F1000-E中会由流分类和虚拟分片重组两个模块对分片报文进行处理。首先流分类会对到达设备的报文进行标识,如果是非首片的IP报文,流分类模块会将这个报文打上和其首片报文相同的标记,交给后续模块处理。NAT模块根据这个标识就可以判断如何对非首片的IP报文进行NAT转换了。
而虚拟分片重组所解决的就是报文乱序到达设备的情况,也就是使用上面的第一种方法对分片的报文进行NAT转换。
最后我们来介绍一下多核产品特有的NAT无限连接。
顾名思义,NAT无限连接就是内网通过NAT访问外网不会受到公网地址数量的影响,并发访问的数量只与设备的最大会话数相关。
前面我们讲到,设备在判断从外网进入内网的报文是否合法是采用了五元组匹配,源地址、源端口号、协议类型、目的地址、目的端口号必须完全一样设备才会唯一确认一个表项。这里我们可以做一个实验,配置NAT设备的公网地址只有一个,并且配置成了高优先级。也就是说在内网所有的PC全部使用相同的协议访问外网同一台服务器、同一个端口的情况下,SecPath F1000-E可以支持64512个并发会话。
<SecPath F1000-E>display session statistics
Current session(s):64514
Current TCP session(s): 1
Half-Open: 0 Half-Close: 0
Current UDP session(s): 64512
Current ICMP session(s): 0
Current RAWIP session(s): 0
Current relation table(s): 0
Session establishment rate: 0/s
TCP Session establishment rate: 0/s
UDP Session establishment rate: 0/s
ICMP Session establishment rate: 0/s
RAWIP Session establishment rate: 0/s
Received TCP: 100945 packet(s) 22944126 byte(s)
Received UDP: 1222623 packet(s) 63581139 byte(s)
Received ICMP: 630395 packet(s) 17777039 byte(s)
Received RAWIP: 0 packet(s) 0 byte(s)
Dropped TCP: 0 packet(s) 0 byte(s)
Dropped UDP: 0 packet(s) 0 byte(s)
Dropped ICMP: 0 packet(s) 0 byte(s)
Dropped RAWIP: 0 packet(s) 0 byte(s)
如果访问的目的地址有两个,则并发会话数可以达到129024个:
<SecPath F1000-E>display session statistics
Current session(s):129026
Current TCP session(s): 0
Half-Open: 0 Half-Close: 0
Current UDP session(s): 129024
Current ICMP session(s): 0
Current RAWIP session(s): 0
Current relation table(s): 0
Session establishment rate: 0/s
TCP Session establishment rate: 0/s
UDP Session establishment rate: 0/s
ICMP Session establishment rate: 0/s
RAWIP Session establishment rate: 0/s
Received TCP: 150635 packet(s) 62257395 byte(s)
Received UDP: 2940678 packet(s) 152925584 byte(s)
Received ICMP: 630395 packet(s) 17777039 byte(s)
Received RAWIP: 0 packet(s) 0 byte(s)
Dropped TCP: 0 packet(s) 0 byte(s)
Dropped UDP: 0 packet(s) 0 byte(s)
Dropped ICMP: 0 packet(s) 0 byte(s)
Dropped RAWIP: 0 packet(s) 0 byte(s)
从下面的详细会话表项可以看到,经过NAT转换后,相同的源地址+端口可以与不同的目的地址+端口建立会话对应关系。
Initiator:
Source IP/Port : 192.168.200.3/52024
Dest IP/Port : 218.197.70.3/5000
VPN-Instance/VLAN ID/VLL ID:
Responder:
Source IP/Port : 218.197.70.3/5000
Dest IP/Port : 218.197.70.200/65535
VPN-Instance/VLAN ID/VLL ID:
Pro: UDP(17) App: unknown State: UDP-OPEN
Start time: 2011-05-28 17:24:12 TTL: 9881s
Root Zone(in): Private
Zone(out): Public
Received packet(s)(Init): 2 packet(s) 104 byte(s)
Received packet(s)(Reply): 0 packet(s) 0 byte(s)
Initiator:
Source IP/Port : 192.168.200.3/50215
Dest IP/Port : 218.197.70.4/5000
VPN-Instance/VLAN ID/VLL ID:
Responder:
Source IP/Port : 218.197.70.4/5000
Dest IP/Port : 218.197.70.200/65535
VPN-Instance/VLAN ID/VLL ID:
Pro: UDP(17) App: unknown State: UDP-OPEN
Start time: 2011-05-28 17:18:28 TTL: 9697s
Root Zone(in): Private
Zone(out): Public
Received packet(s)(Init): 6 packet(s) 312 byte(s)
Received packet(s)(Reply): 0 packet(s) 0 byte(s)
而在真实的网络中,内网PC访问的目的IP和端口的组合可能有几千甚至上万个。那么NAT所能支持的并发数量也就变成了64512与目的地址数量的乘积,在理论上已经接近无限个了。
虽然NAT可以解决IP地址空间不足,也可以很好地隐藏内部网络的拓扑结构,使网络更安全。但是它毕竟修改了报文的内容,随着应用场景的不断增多,相信还有很多需要NAT进行特殊处理的地方,这些地方有待于我们继续挖掘、探讨,使得NAT技术更加完善。