NAT的全然分析及其UDP穿透的全然解决方式
一:基本术语
防火墙
防火墙限制了私网与公网的通信,它主要是将(防火墙)觉得未经授权的的包丢弃,防火墙仅仅是检验包的数据,并不改动数据包中的IP地址和TCP/UDPport信息。
网络地址转换(NAT)
当有数据包通过时,网络地址转换器不仅检查包的信息,还要将包头中的IP地址和port信息进行改动。以使得处于NAT之后的机器共享几个仅有的公网IP地址(一般是一个)。网络地址转换器主要有两种类型.
P2P应用程序
P2P应用程序是指,在已有的一个公共server的基础上,并分别利用自己的私有地址或者公有地址(或者两者兼备)来建立一个端到端的会话通信。
P2P防火墙
P2P防火墙是一个提供了防火墙的功能的P2P代理,可是不进行地址转换.
P2P-NAT
P2P-NAT 是一个 P2P代理,提供了NAT的功能,也提供了防火墙的功能,一个最简的P2P代理必须具有锥形NAT对Udp通信支持的功能,并同意应用程序利用Udp打洞技术建立强健的P2P连接。
回环转换
当NAT的私网内部机器想通过公共地址来訪问同一台局域网内的机器的时,NAT设备等价于做了两次NAT的事情,在包到达目标机器之前,先将私有地址转换为公网地址,然后再将公网地址转换回私有地址。我们把具有上叙转换功能的NAT设备叫做“回环转换”设备。
二:NAT分类
能够分为基础NAT与网络地址和port转换(NAPT)两大类
(一):基础NAT
基础NAT 将私网主机的私有IP地址转换成公网IP地址,但并不将TCP/UDPport信息进行转换。基础NAT一般用在当NAT拥有非常多公网IP地址的时候,它将公网IP地址与内部主机进行绑定,使得外部能够用公网IP地址訪问内部主机。(实际上是仅仅将IP转换,192.168.0.23 <-> 210.42.106.35,这与直接设置IP地址为公网IP还是有一定差别的,特别是对于企业来说,外部的信息都要经过统一防火墙才干到达内部,可是内部主机又能够使用公网IP)
(二):网络地址和port转换 (NAPT)
这是最普遍的情况,网络地址/port转换器检查、改动包的IP地址和TCP/UDPport信息,这样,很多其它的内部主机就能够同一时候使用一个公网IP地址。
请參考[RFC1631]和[RFC2993]及[RFC2663]这三个文档了解很多其它的NAT分类和术语信息。另外,关于NAPT的分类和术语,[RFC2663]做了很多其它的定义。当一个内部网主机通过NAT打开一个“外出”的TCP或UDP会话时,NAPT分配给这个会话一个公网IP和port,用来接收外网的响应的数据包,并经过转换通知内部网的主机。这样做的效果是,NAPT在 [私有IP:私有port] 和[公网IP:公网port]之间建立了一个port绑定。
port绑定指定了NAPT将在这个会话的生存期内进行地址转换任务。这中间存在一个这种问题,假设P2P应用程序从内部网络的一个[私有IP地址:port]对同一时候发出多条会话给不同的外网主机,那么NAT会如何处理呢?这又能够分为锥形NAT (CONE NAT)与对称NAT (SYMMTRIC NAT)两大类来考虑:
A.锥形NAT
(为什么叫做锥形呢?请看下面图形,终端和外部server,都通过NAT分派的这个绑定地址对来传送信息,就象一个漏斗一样,筛选并传递信息)
当建立了一个 [私有IP:port]-[公网IP:port] port绑定之后,对于来自同一个[私有IP:port]会话,锥形NATserver同意发起会话的应用程序 反复使用这个port绑定,一直到这个会话结束才解除(port绑定)。
比如,如果 Client A(IP地址信息如上图所看到的)通过一个锥形NAT 同一时候发起两个外出的连接,它使用同一个内部port(10.0.0.1:1234)给公网的两台不同的server,S1和S2。锥形NAT 仅仅分配一个公网IP和port(155.99.25.11:62000)给这个两个会话,通过地址转换能够确保 Client使用port的“同一性”(即这个Client仅仅使用这个port)。而基础NATs和防火墙却不能改动经过的数据包port号,它们能够看作是锥形NAT的精简版本号。
进一步分析能够将CONE NAT受限制锥形NAT (RESTRICT CONE) 与port受限锥形NAT (PORT RESTRICT CONE) 三大类,下面是具体论述: 分为全双工锥形NAT (FULL CONE) ,
1.全双工锥形NAT
当内部主机发出一个“外出”的连接会话,就会创建了一个公网/私网 地址,一旦这个地址对被创建,全双工锥形NAT会接收随后不论什么外部port传入这个公共port地址的通信。因此,全双工锥形NAT有时候又被称为"混杂"NAT。
2.受限制锥形NAT
受限制的锥形NAT会对传入的数据包进行筛选,当内部主机发出“外出”的会话时,NAT会记录这个外部主机的IP地址信息,所以,也仅仅有这些有记录的外部IP地址,可以将信息传入到NAT内部,受限制的锥形NAT 有效的给防火墙提炼了筛选包的原则——即限定仅仅给那些已知的外部地址“传入”信息到NAT内部。
3.port受限锥形NAT
port受限制的锥形NAT,与受限制的锥形NAT不同的是:它同一时候记录了外部主机的IP地址和port信息,port受限制的锥形NAT给内部节点提供了同一级别的保护,在维持port“同一性”过程中,将会丢弃对称NAT传回的信息。
B.对称NAT
对称NAT,与Cone NAT是大不同样的,并不正确会话进行port绑定,而是分配一个全新的公网port 给每个新的会话。
还是上面那个样例:假设 Client A (10.0.0.1:1234)同一时候发起两个 "外出" 会话,分别发往S1和S2。对称Nat会分配公共地址155.99.25.11:62000给Session1,然后分配还有一个不同的公共地址155.99.25.11:62001给Session2。对称Nat可以差别两个不同的会话并进行地址转换,由于在 Session1 和 Session2中的外部地址是不同的,正是由于这样,Client端的应用程序就迷失在这个地址转换边界线了,由于这个应用程序每发出一个会话都会使用一个新的port,无法保障仅仅使用同一个port了。
在TCP和UDP通信中,(究竟是使用同一个port,还是分配不同的port给同一个应用程序),锥形NAT和对称NAT各有各的理由。当然锥形NAT在依据怎样公平地将NAT接受的连接直达一个已创建的地址对上有很多其它的分类。这个分类一般应用在Udp通信(而不是Tcp通信上),由于NATs和防火墙阻止了试图无条件传入的TCP连接,除非明白设置NAT不这样做。
三:NAT对session的处理
下面分析NAPT是根据什么策略来推断是否要为一个请求发出的UDP数据包建立Session的.主要有一下几个策略:
A. 源地址(内网IP地址)不同,忽略其他因素, 在NAPT上肯定相应不同的Session
B. 源地址(内网IP地址)同样,源port不同,忽略其他的因素,则在NAPT上也肯定相应不同的Session
C. 源地址(内网IP地址)同样,源port同样,目的地址(公网IP地址)同样,目的port不同,则在NAPT上肯定相应同一个Session
D. 源地址(内网IP地址)同样,源port同样,目的地址(公网IP地址)不同,忽略目的port,则在NAPT上是怎样处理Session的呢?
A,B,C三种情况的都是比較简单的,能够非常easy的实现.而D的情况就比較复杂了.所以D情况才是我们要重点关心和讨论的问题。
四:全然解决方式
下面针对四种SESSION与四种NAT的全然解决方式,为了方便将使用下面缩写形式:
C代表 CONE NAT
S代表SYMMETRIC NAT,
FC代表 FULL CONE NAT,
RC代表 RESTRICT CONE NAT,
PC 代表 PORT RESTRICT CONE NAT.
首先根据CLIENT (客户)端在NAT后 的个数不同能够分为两大类:
TYPE ONE :一个在NAT后 + 一个在公网中.
这样的情况下能够分为两大类:
A. S VS 公网:此种情况下,因为公网的地址在一个SESSION内是不变的,所以能够打洞是能够成功的.
B. C VS 公网: 与上面相似,这样的情口下打洞是能够成功的.
TYPE TWO:两个客户都在NAT后面.
这样的情况下也能够细分为两大类:
A. 当中一个NAT 是 S(SYMMETRIC NAT) 型的,既:S VS C或者是S VS S .
以下论证这样的情口下依照常规打洞是行不通的,在常规打洞中,全部的客户首先登陆到一个server上去.server记录下每一个客户的[公网IP:port],然后在打洞过程中就使用这个记录的值,然而对于S型的NAT来说,它并不绑定[私网IP:port]和[公网IP:port]的映射.所以在不同的SESSION中,NAT将会又一次分配一对[公网IP:port].这样一来对于S型的NAT来说打洞的[公网IP:port]与登记在server上的[公网IP:port]是不同的.并且也没有办法将打洞的[公网IP:port]通知到还有一个位于NAT下的client, 所以打洞是不会成功的.然而假设还有一个client是在公网时,打洞是能够的.前面已经论证了这样的情况.
这样的情况下的解决方式是仅仅能通过port预測来进行打洞,详细解决方法例如以下:比如(以两个都是S型的为例) NAT A 分配了它自己的UDPport62000,用来保持 clientA 与serverS的通信会话, NAT B 也分配了31000port,用来保持clientB与serverS 的通信会话。通过与 serverS的对话,clientA 和 clientB都相互知道了对方所映射的真实IP和port。
clientA发送一条UDP消息到138.76.29.7:31001(请注意到port号的添加),同一时候clientB发送一条UDP消息到155.99.25.11:62001。假设NAT A 和NAT B继续分配port给新的会话,而且从A-S和B-S的会话时间消耗得并不多的话,那么一条处于clientA和clientB之间的双向会话通道就建立了。
clientA发出的消息送达B导致了NAT A打开了一个新的会话,而且我们希望NAT A将会指派62001port给这个新的会话,由于62001是继62000后,NAT会自己主动指派给 从serverS到clientA之间的新会话的port号;相似的,clientB发出的消息送达A导致了 NAT B打开了一个新的会话,而且我们希望 NAT B将会指派31001这个port给新的会话;假设两个client都正确的推測到了对方新会话被指派的port号,那么这个 clientA-clientB的双向连接就被打通了。其结果例如以下图所看到的:
明显的,有很多因素会导致这种方法失败:假设这个预言的新port(62001和31001) 恰好已经被一个不相关的会话所使用,那么NAT就会跳过这个port号,这个连接就会宣告失败;假设两个NAT有时或者总是不依照顺序来生成新的port号,那么这种方法也是行不通的。
假设隐藏在NATA后的一个不同的clientX(或者在NAT B后)打开了一个新的“外出”UDP 连接,并且不管这个连接的目的怎样;仅仅要这个动作发生在clientA 建立了与serverS的连接之后,clientA 与 clientB 建立连接之前;那么这个无关的clientX 就会趁人不备地“偷” 到这个我们渴望分配的port。所以,这种方法变得如此脆弱并且不堪一击,仅仅要不论什么一个NAT方包括以上碰到的问题,这种方法都不会奏效。
在处于 cone NAT 系列的网络环境中这种方法还是有用的;假设有一方为 cone NAT 而另外一方为 symmetric NAT,那么应用程序就应该预先发现另外一方的 NAT 是什么类型,再做出正确的行为来处理通信,这样就增大了算法的复杂度,而且减少了在真实网络环境中的普适性。
最后,假设P2P的一方处在两级或者两级以上的NAT以下,而且这些NATS 接近这个client是SYMMETRIC NAT的话,port号预言是无效的!
因此,并不推荐使用这种方法来写新的P2P应用程序,这也是历史的经验和教训!
B. 两个都是CONE NAT型的.
这样的情况下能够分为六大类型:
A: FC + FC
B: FC + RC
C: FC + PC
D: PC + RC
E: PC + PC
F: RC + RC
尽管有这么多种情况,可是由于CONE NAT 的特性,所以还是非常好办的,由于对于CONE NAT 来说,在同一个SESSION中它会绑定一对[私网IP:port]和[公网IP:port]的映射,所以它们打洞用的[公网IP:port]与登记在server上的[公网IP:port]是一致的,所以打洞是能够行的通的.
综上所述,就已经全然的概括了全部类型的NAT之间的可能的通信情况了.而且都提供了可行的解决方式.
五:对前一阶段的总结
1.前一阶段使用的打洞方法是有缺陷的,它仅仅适应于两个都是FULL CONE NAT的类型的CLIENT(client).下面论证它不适应于两个都是CONE NAT的类型中的
B: FC + RC
C: FC + PC
D: PC + RC
E: PC + PC
F: RC + RC
这五种情况.
由于对于受限的NAT它登记了外出包的[IP地址&port],它只接受这些已登记地址发过来的包,所以它们报告server的port只能接受来自server的包.不能接受来自还有一client的包.所曾经一阶段的打洞方法是不可行的.
六: 存在的问题
依照理论.NAT将在一定时间后关闭UDP的一个映射,所以为了保持与server可以一直通信,server必需要发送UDP心跳包,来保持映射不被关闭.这就需要一个合适的时间值.