详解:NAT原理及在VxWorks上的实现
扫描二维码
随时随地手机看文章
Internet的最初设计,并没有考虑到需要支持目前这样庞大的互联网,因此在IPv4的设计当中,IP地址仅使用了32bit来标识网络中的一个节点设备,虽然这很好地解决了IP数据报的对齐问题,但随着Internet的迅猛发展,加上一些不合理的地址分配方式,目前IP地址已严重缺乏,IP地址短缺已成为目前Internet所面临的最大问题之一。
为了节约IP地址资源,IETF抛弃了传统的地址分类方式(把IP地址空间人为地划分为A、B、C、D类地址的方式)。开始使用在RFC 1918中指定的CIDR(Classless Inter-Domain Routing)。同时为了解决IP地址耗损的问题,在RFC 1631中提出了使用NAT来解决共用IP地址访问Internet的问题。
1 NAT 概况
NAT是把一个网络中使用的IP地址翻译成能被另一个网络识别的IP地址。一个网络被指定为内部网络,另一个为外部网络。通常,一个公司把自己的本地内部网络地址映射到一个或多个全局外部IP地址,并把收到的包中的全局IP地址解释成本地IP地址。这也有助于安全,因为每个出去和进来的请求都必须经过一个翻译过程,这是一个认证请求或把它与以前请求匹配的过程。
NAT包含在路由器中,通常也是防火墙的一部分。网络管理员创建一个NAT表,用它来实现全局到本地和本地到全局地址的映射。NAT也可以和策略利用路由一起使用。NAT可以静态定义,也可以根据IP地址池动态进行。
NAT的描述详见RFC 1631。它讨论了NAT与CIDR的关系,这是一个解决IP地址耗尽的方法。NAT通过区别公共IP地址和私有IP地址而减少了对公共IP地址的需求。CIDR把公共IP地址聚集在一起,减少了IP地址的浪费。
2 NAT 原理
在传统的标准的TCP/IP通信过程中,所有的路由器仅仅是充当一个中间人的角色,也就是通常所说的存储转发,路由器并不会对转发的数据包进行修改,比如对于以太网接口,路由器除了将源MAC 地址换成自己的MAC 地址以外,路由器不会对转发的数据包做任何修改。NAT(Network Address Translate,网络地址翻译)恰恰是出于某种特殊需要而对数据包的源IP地址、目的IP地址、源端口、目的端口进行改写的操作。
从原理的角度可以将NAT分成了两种类型,即源NAT(SNAT)和目的NAT(DNAT),顾名思义,所谓SNAT就是改变转发数据包的源地址,所谓DNAT就是改变转发数据包的目的地址。
3 NAT 的VxWorks 实现
3.1 VxWorks的底层接口概况
3.1.1 VxWorks MUX 接口层
在VxWorks中,TCP/IP协议栈使用MUX接口去和数据链路层通信,MUX接口的目的是隔离数据链路层和网络层。MUX接口之上是网络协议层,比如TCP/IP、 MUX_PROTO_OUTPUT、 MUX_PROTO_SNARF等协议,在MUX之下为网络硬件的驱动程序。MUX接口层提供一套接口去完成协议和驱动注册,协议和驱动之间数据接收、发送,Multicast地址访问,MUX ioctl等工作。整个层次结构如图1所示。
3.1.2 VxWorks 中对IP数据包的截获
要在VxWorks中实现NAT,必须实现两个基本操作:IP数据包的截获与IP数据包的伪装处理。
对于VxWorks协议栈来讲,NAT的存在是透明的。所以,要实现NAT的功能,必须在VxWorks网络协议栈处理数据包之前截获数据。要实现这一点,VxWorks为我们提供了两类钩子函数,截获以太帧的EtherHook和截获IP数据包的IpFilterHook。
其中EtherHook又包括EtherInputHook和EtherOutputHook,分别用来截获接收和发送的以太帧。用户可以通过EtherInputHookAdd和EtherOutputHookAdd来分别进行安装。
而IpFilterHook提供对IP数据包的截获,它只对应一个钩子函数,用IpFilterHookAdd来进行安装。当收到一个IP数据包的时候,IpFilterHook会被自动调用,从而达到对IP数据包截获的目的。
对比两种接口,EtherInputHookAdd将调用MuxBind去添加一个MUX_PROTO_SNARF协议,这样可以得到进入MUX接口层的所有数据包。而由IpFilterHookAdd安装的IpFilterHook,不属于MUX接口层,仅仅用来截获IP数据包,而不会接收到非IP数据包。
鉴于以上的区别,我们使用IpFilterHookAdd函数安装的IpFilterHook来截获IP数据包比较合适,参见图2。
3.2 NAT伪装策略
3.2.1 网络接口
网络接口是VxWorks的一个内核对象,它是由网络驱动程序注册的。它在内核中用于标识网络设备的驱动程序,包含着该网络设备特有的属性、配置及操作接口等。而这个驱动程序可以驱动一个特定型号的网络芯片,比如I82557,RTL 8139等,也可以驱动一些其他类型的设备,比如通过Serial Port、CompactPCI Bus、Loopback等。在VxWorks中,接收到的IP数据被保存在一个mBlk的结构当中。该结构除保存数据内容外,还保存了管理数据内容的信息结构以及接口信息。
3.2.2 哪些IP数据包需要伪装
在做NAT地址映射时,我们需要判断对哪些IP包进行伪装(NAT变换)。我们通过下面这个实例来进行讲解(见图3)。
在这个实例中,网关通过网络接口If0连接到局域网中,并通过If1连接到Internet上,同时,网关启用NAT功能。此时,位于局域网中的主机A如果想访问Internet上10.2.4.0/24网段的主机B,最好的方法是通过网关上的NAT。
那么,具体哪些包需要进行NAT变换呢?我们先根据源地址和目的地址来划分网关可能收到的包的类型。
(1)接口If0收到的IP数据包,目的地址为网关If0接口的IP地址。
(2)接口If0收到的IP数据包,目的地址为网关If1接口的IP地址。
(3)接口If0收到的IP数据包,目的地址非网关任一接口的地址的私网IP地址。
(4)接口If0收到的IP数据包,目的地址非网关任一接口的地址的公网IP地址。
(5)接口If1收到的IP数据包,目的地址为If1接口的IP地址。
(6)接口If1收到的IP数据包,目的地址非If1接口的IP地址。
对于前面3种情况,NAT不进行任何处理,直接交给VxWorks网络协议栈,由协议栈来做进一步的处理。
对于第4种情况,符合NAT变换的需求,NAT将改变原IP包的源地址为网关的外出口地址,同时选择网关该接口未分配的端口来修改原IP包中的源端口,并添加该记录到NAT映射表内。最后把IP包送到If1接口,然后发送到目的主机。
对于第5种情况,我们将收到的IP数据包送到NAT处理。通过查找NAT映射表,决定是否将其目标地址转换为LAN中的某一个地址,还是不做任何处理,直接归还给协议栈。对于第6种情况,我们这里也简单地直接归还给协议栈进行处理。[!--empirenews.page--]
3.3 NAT 映射表及timer管理
3.3.1 NAT 映射表
对于每一个需要进行地址翻译的IP数据包,内核必须知道如何翻译它。NAT 映射表就是用来解决这个问题的。NAT 映射表中记录有足够标识一个连接的所有信息:协议类型、源地址、源端口、目的地址、目的端口、NAT地址、NAT端口等。通过IP数据包中携带的信息可以在NAT表中找到最匹配的一项。在实现当中,我们采用表1的结构来表示一个映射表项。
3.3.2 为什么NAT 映射表项需要设置timer
为了避免通过NAT进行通信的主机突然崩溃后,出现残留的映射表项占据系统资源的情况。在每个NAT映射表项中,我们使用了一个软件定时器来指示这个映射表项是否超时。如果在一段时间内这个表项没有被访问过,从而导致定时器超时,NAT将清除这个表项,以减少系统资源消耗。在这个NAT的实现过程中,为了使TCP/IP协议栈能够正常工作,针对不同的协议以及协议的不同阶段,我们使用了不同的默认超时值。如表2所示。
3.4 NAT 映射表管理
3.4.1 NAT 映射表的创建、查找及删除
在NAT的实现过程当中,如何快速地寻找一个IP包在NAT中是否有对应的映射选项,需要一个高效的数据结构和快速的查找算法。
在实现当中,我们选用采用索引查询的散列表来作为存储NAT映射表项的数据结构。使用协议类型值、内部网络地址和端口来计算散列值,并结合映射表项的标志来确定需要做地址翻译的IP数据包。
如果当前的IP数据包是外出的IP数据包,但是没有匹配到一个合适的映射表项,那么NAT将建立一个新的映射表项,添加到散列表中。
如果当前的IP数据包是来自于外部网络的,要么能够匹配到一项合适的映射表项,要么目的端口已经被配置为端口转发(在这种情况下,NAT将依据端口转发配置,在NAT映射表中静态添加一个入口),否则,将不会改变这个IP数据包。
为了避免已经出现异常的连接继续占用系统资源,在每个映射表项的定时器超时后,其回掉函数将删除存储在散列表中的对应的NAT映射表项。
3.4.2 如何互斥地访问NAT映射表
在NAT映射表的处理和映射表项超时处理中,都需要对映射表进行查找、添加和删除操作。为了安全地访问映射表,我们必须同步对NAT映射表的访问。在实现当中,我们使用了VxWorks提供的二进制信号量来保护对NAT映射表的操作。
3.5 TCP session state和TCP sequence number管理
3.5.1 TCP SYN/FIN/RST 状态
对于一个TCP连接,如果NAT收到一个带有RST标志的TCP数据包,我们将NAT映射表中对应表项的定时器超时值置1,那么这个映射表很快将被删除。如果收到一个FIN数据包,那么就重新设置对应表项的定时器超时值为120s。否则,我们设置对应映射表项的定时器超时值为5min。
3.5.2 TCP sequence number 调整
NAT的原理就是通过修改过往IP数据包的内容,来达到伪装IP数据包的目的。
在对部分基于TCP的应用协议(如FTP)的数据包进行NAT变换时,如果由于应用程序支持模块改变了TCP数据包的内容,导致数据包的长度发生变化,那么,为了使当前的TCP连接能够继续正常连接,就必须重新调整TCP的序列号(见图4)。
TCP连接的序列号是在两个方向上进行调整的。调整的原则如下:
如果外出的数据包长度减小,那么当前外出的TCP数据包的序列号将减小,反之则增加。
对于收到的来自于外部网络的ACK 序列号,就要相应地增加和减小了。
这里我们需要注意,由于VxWorks没有使用Real Time来初始化TCP连接的初始序列号,而是使用一个固定的值来初始化它,导致每次重启之后VxWorks的第一次TCP连接都会以相同的序列号开始递增。由于VxWorks的TCP/IP协议栈的这种特征,我们在接收到TCP连接的第一个TCP数据包(带有SYN标志,没有ACK标志)时,要重新初始化已经匹配的NAT映射表项,避免因为TCP连接序列号调整出错。
3.6 端口转发功能
3.6.1 为什么需要端口转发功能
如果有某个处在Internet上的主机想访问NAT服务器后的某个主机,这个连接必须已经被记录在NAT映射表中,但由于某些安全原因,NAT仅仅对由内部网络发起的网络连接有效。当外部IP数据包进入允许NAT功能的接口时,如果NAT找不到合适的映射表项,IP数据包将交给VxWorks协议栈来处理。
为了使NAT能够处理这种由外部网络首先发起的网络连接,NAT允许手工配置一些NAT的映射表项。这项功能就叫端口转发。
3.6.2 端口转发实现过程
由外到内的IP包指的是从公网通过NAT发送到私有网络的IP包。它的源IP是公共IP,目的IP是NAT的公共IP。当截获到一个由外到内的IP包时,NAT就以IP包的目的IP和目的Port加上包的协议类型作为NAT映射表项的匹配查询条件进行搜索。如果找到一个对应的表项,就用表项的Real Src IP和Real Src Port来替换IP包的目的IP和目的Port,而保持IP包的源IP和源Port不变。然后,重新计算TCP或UDP的校验和,再计算IP头的校验和,最后把IP包重新归还给VxWorks的网络协议栈。如果在映射表中没有搜索到对应的表项,则对IP包不作任何处理,直接归还给VxWorks网络协议栈。
3.7 NAT配置接口
为了使NAT能够适应某些变化,我们在实现过程当中加入了对NAT的配置接口,主要对以下两方面需要进行配置。
NAT接口配置:配置在那个允许NAT功能的网络接口上。这个接口是和外部网络相连的,有唯一的全局IP地址。
端口转发映射表配置:配置NAT可以对那些由外部网络发起的网络连接进行地址转换,以及如何进行地址转换。
3.8 NAT如何处理IP分片
NAT本身还应该考虑IP数据包的分片。但是在分片的IP数据包中,除了第一个IP数据包带有源、目的端口信息以外,后续的IP分片都没有端口信息。
这样,IP数据包分片的这个特征给我们的NAT处理带来了很多不便。因此,在这次的实现过程中,我们的NAT实现暂时不支持分片的IP数据包。
3.9 NAT的测试
如图3所示,主机A通过NAT访问主机B上的HTTP服务器,主机B通过手工配置在NAT上的映射表项访问主机A上的TFTP服务器。
整个过程非常良好,TCP包和UDP包以及Port-Forward功能也成功得到了验证。[!--empirenews.page--]
4 NAT的未来
NAT这项技术主要是为了解决IP地址空间不足。在NAT功能的支持下,内部网络可以使用一个公共的IP地址访问外部网络,因此,它很好地隐藏内部网络的网络拓扑结构,也使网络更安全。由于这些特点,NAT也常常是作为Firewall的重要部分一起提供的,但是它并不是Firewall。由于NAT可以带来一定的安全性,相信即使在IPv6的时代,它还是能够继续应用。