Udp打洞文章大全NAT 穿越技术荟萃.docx
《Udp打洞文章大全NAT 穿越技术荟萃.docx》由会员分享,可在线阅读,更多相关《Udp打洞文章大全NAT 穿越技术荟萃.docx(25页珍藏版)》请在冰豆网上搜索。
Udp打洞文章大全NAT穿越技术荟萃
Udp打洞,判断Nat网络类型
一种基于UDP协议实现P2P智能穿越NAT的方案
范艳阳,刘若尧
1北京邮电大学通信工程学院计算机中心,北京(100876)
E-mail:
fanyanyang@
摘要:
由于目前NAT(NetworkAddressTranslation,网络地址转换协议)的广泛运用,处于Internet上的公网主机与处于NAT之后的主机建立对等连接是实现P2P(Peer-To-Peer,点对点)通信很关键的问题。
本文在分析了基于UDP(UserDatagramProtocol,用户数据报)协议穿透NAT的实现原理的基础上,给出了一个基于UDP协议,根据不同NAT类型情况自适应选择NAT穿越方案,实现P2P通信的实现方案。
关键词:
UDP,NAT,P2P
中图分类号:
TP273
1.引言
NAT技术不仅可以暂时解决IPv4中IP地址分配的限制,而且还可以隐藏内部的网络地址信息,使外界无法直接访问网内的网络资源,保护了内部网络,所以NAT在防火墙中也得到了非常广泛的应用。
基于以上原因,NAT在现有的网络中是必不可少的[1]。
随着P2P技术的广泛应用,更多的网内主机需要参与到P2P网络中来。
由于NAT的存在,局域网(私网)IP地址在Internet上是不可见的,这也就造成了Internet上的主机不能主动访问NAT之后的主机,而位于NAT之后的主机间更是无法相互识别和通信[2]。
所以P2P网络应用必须解决穿透NAT实现主机间相互发现、相互定位和相互寻址的关键技术。
以建立起一个对等连接,进行对等通讯。
2.UDP协议穿越NAT的原理及特点
2.1中继转发方式
这种方式是最简单的,也是一种比较可靠的P2P通信方式。
实现原理为位于两个不同NAT之后的两台主机,都已经各自发起UDP连接到一个众所周知的、具有合法公网IP地址的服务器上.以两者间的通讯由服务器来中转完成。
但是这种通信方式效率底下,消耗了服务器的处理能力和网络带宽,同时主机之间的信息等待时间加长,且容纳P2P用户数有限。
2.2反向连接方式
这种方式仅工作在只有一个主机A在NAT后面,另外的主机B拥有合法公网IP地址[2]。
在试图建立一个直接到A的连接失败后,主机B能够通过服务器S来中转一个请求到主机A,使A发出一个“反向的”连接请求到主机B。
主机A在收到这个要求后,开始发起一个到B的公网IP地址和端口号上UDP连接。
这样A与B就可以相互建立连接了。
目前大部分的P2P系统都采用这种方式。
这种工作方式的主要局限性就是仅适合通讯点中的一方在NAT的后面。
如果通讯点都在NAT后面,那么这种方式就行不通了。
因此反向连接不是一种通用的解决问题方法.
2.3UDP穿孔技术
UDP穿孔技术(UDPHolePunching)是根据建立好的NAT协议来允许P2P应用程序“punchholes”(穿孔)通过NAT和防火墙并且相互之间建立直接的连接技术[3]。
以下考虑两种情况典型情况——主机分别位于不同NAT后和主机位于相同NAT后。
2.3.1主机位于不同NAT后面
如果两个主机A和B都有私网IP地址并且位于不同的NAT后面。
P2P应用程序运行在主机A和B以及服务器S上。
假设主机A想要与主机B直接建立一个UDP会话。
那么B所在的NAT通常将会丢弃这个消息,因为源地址和端口号与和他所发起的外部会话建立连接的目的地址和端口号不匹配。
类似的,B也我发主动建立与A的连接。
UDP穿孔的方式是:
A发送UDP请求到B的公共地址,同时通过服务器S转发一个消息到达B,消息内容是要求B发送UDP请求到A的公共地址。
A的请求直接到达B的公共地址的消息将会使得A所在的NAT在A的私有地址和B的公共地址之间建立一个新的通讯会话(即打一个孔),同时B的消息(A通过S要求B发送的)到达A的公共地址将会使得B所在的NAT在B的私有地址和A公共地址之间建立一个新的通讯会话(也打了一个孔)[4]。
一旦新的UDP会话在每一方向上都建立成功,那么主机A和B就能够相互直接通信而不再需要借助服务器S了。
2.3.2主机位于相同NAT后面
两台主机处于相同NAT后,即双方在同一私网内的情况下。
由于双方并不知道这种情况,主机A如果需要连接主机B,仍然向B的外网地址发起连接请求,采用打孔方案进行连接。
只有在NAT允许内部的网络主机能够和内部的其他主机进行UDP会话的情况下连接也是可以实现的,但是显然这种方式是完全没必要的。
同理,当一台主机位于NAT后,另一台主机为公网地址时,这种方式虽然可以建立直接连接,但仍然显得过于麻烦[5]。
由此可见,在通信双方同在相同NAT内部,或只有一方在NAT内部另一方在公网环境中时,打孔方式效率较低下,增加了通信建立的反应时间,而且还对服务器S产生不必要的额外负担。
3.一种自适应的NAT穿越策略的方案
这种穿越策略的实现,需要一台具有公网地址的服务器,客户端两部分的支持。
且此P2P应用中的每一个用户,都拥有一个唯一的标识ID。
3.1服务器功能设计
穿越协助服务器包括三个服务:
1)网络类型监测服务。
此服务接收用户请求并检测此用户的网络类型,内网/外网的IP、PORT信息,并将这些信息返回给用户,以便用户根据这些信息选择策略。
2)查询服务。
如果某ID的主机已经在此服务器上注册过,则其他主机可以通过此ID,在服务器上查询到该用户的网络信息。
3)转发服务。
此服务会根据已注册用户的信息,把某用户的UDP包转发给另一个用户。
转发的消息包可以分为两类:
一类是穿越请求,此类请求用于协助主机间的NAT打孔。
另一类是是转发通信信息,当所有直接建立UDP连接的尝试失败后,此服务可以转发用户的通信信息,建立用户间间接的通信。
3.2客户端自适应的NAT穿越策略设计
假设在位置网络环境下,某主机A需要与主机B建立P2P通信。
首先,任意主机在启动时都与协助服务器进行通信,获取自身的网络类型与地址信息,如果是在NAT内部则得到的内外网两种地址信息,且始终保持和协助通信服务器的连接,以便接收服务器的消息。
自适应穿越NAT实现P2P通信方案的流程如图1所示:
图1自适应NAT穿越策略流程图
实现原理如下:
当主机A得到与主机B建立连接的命令并得到其ID后,首先向协助服务器发出请求,询问主机B所在的网络类型与地址信息。
查询成功后主机A开始尝试运用策略尝试与主机B建立直接连接:
1)判断主机B是否在NAT内部,如果B不在NAT内部,则无论A的网络类型如何都可以直接向B发出连接请求,即便A在NAT内部也不会影响直接通信的建立。
2)如果主机B在NAT内部,则主机A需要判断自己所在的网络类型,如果主机A不在NAT内部则采用反向连接策略,主机A向服务器发送请求B反向连接的请求,服务器接到此请求后向主机B发送反向连接请求和主机A的地址信息,B收到服务器请求后,尝试主动与主机A进行通信连接。
3)如果主机A与主机B都在NAT内部,这时需要判断双方是否处于同一NAT中,主机A比较自己与主机B的外网地址,如果地址相同则说明在同一NAT中,主机A直接向B的内网地址发出连接请求即可[6]。
4)如果双方主机都在NAT内部,且外网地址不相同,则说明A与B不在同一NAT中,需要使用NAT打孔技术。
主机A向主机B发送连接请求的同时,向服务器发出反向连接请求,并等待接收B的反向连接信息。
以上过程后,客户端便完成了直接通信连接的尝试,主机A等待B发送的连接确认信息。
如果接收到连接确认信息,则证明直接连接建立成功,双发开始P2P通信。
如果主机A等待主机B的连接信息超时,则证明NAT穿越失败,双方无法建立直接连接。
双方只能建立间接通信连接,主机A所有的通信消息都通过协助服务器转发给主机B。
4.结论
以上策略在建立连接的成功率和效率以及服务器开销方面取得了较好的平衡,根据不同网络特点,动态选择连接策略。
对每种情况,动态选取最佳的连接方案。
目前,世界上有关P2P的研究项目层出不穷,应用也越来越广。
P2P身后所蕴藏着无比的创造力是对P2P寄予厚望的原因所在。
在可以预见的未来,随着对P2P研究的进一步深入和关注P2P的企业逐渐增多,P2P必将进入一个飞速发展的新时期。
参考文献
[1]Postel.J.UserDatagramProtocol[DBPOL].RFC768.1980.
[2]ThomsLee.Windows2000TCPPIP协议和服务技术参考[M].北京:
人民邮电出版社,2001.
[3]Ford,Srisuresh&Kegel.Peer-to-Peer(P2P)communicationacrossmiddleboxes[DBPOL].http:
PPwww.ietf.orgPids.By.wgPmid2com.html,2003.
[4]RodrigoRodrigues,BarbaraLiskov,LiubaShrira.TheDesignofaRobustPeer-to-PeerSystem[DBPOL].http:
PPwww.pmg.lcs.mit.eduP~RodrigoPew02-robust.pdf,2002.
[5]DanielSenie.NetworkAddressTranslator(NAT)-FriendlyAppli2cationDesignGuidelines[DBPOL].RFC3235,2002.
[6]EgevangK.FrancisP.TheIPnetworkaddresstranslator(NAT)[DBPOL].RFC1631,1994.
首先,ClientA登录服务器,NATA为这次的Session分配了一个端口60000,那么ServerS收到的ClientA的地址是202.187.45.3:
60000,这就是ClientA的外网地址了。
同样,ClientB登录ServerS,NATB给此次Session分配的端口是40000,那么ServerS收到的B的地址是187.34.1.56:
40000。
此时,ClientA与ClientB都可以与ServerS通信了。
如果ClientA此时想直接发送信息给ClientB,那么他可以从ServerS那儿获得B的公网地址187.34.1.56:
40000,是不是ClientA向这个地址发送信息ClientB就能收到了呢?
答案是不行,因为如果这样发送信息,NATB会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。
现在我们需要的是在NATB上打一个方向为202.187.45.3(即ClientA的外网地址)的洞,那么ClientA发送到187.34.1.56:
40000的信息,ClientB就能收到了。
这个打洞命令由谁来发呢,呵呵,当然是ServerS。
总结一下这个过程:
如果ClientA想向ClientB发送信息,那么ClientA发送命令给ServerS,请求ServerS命令ClientB向ClientA方向打洞。
呵呵,是不是很绕口,不过没关系,想一想就很清楚了,何况还有源代码呢(侯老师说过:
在源代码面前没有秘密),然后ClientA就可以通过ClientB的外网地址与ClientB通信了。
注意:
以上过程只适合于ConeNAT的情况,如果是SymmetricNAT,那么当ClientB向ClientA打洞的端口已经重新分配了,ClientB将无法知道这个端口(如果SymmetricNAT的端口是顺序分配的,那么我们或许可以猜测这个端口号,可是由于可能导致失败的因素太多,我们不推荐这种猜测端口的方法)。
所有主机先登录服务器,服务器记录各个主机的地址和端口。
当A要与B通讯时,A向服务器发出申请,获得B的地址和端口,然后服务器再通知B,并把A的地址和端口告诉B,然后双方分别向对方发出信号,收到对方信号时发出回应,如此重复若干次,直到双方都收到对方回应为止。
NAT有多种类型,大体分两种情况:
1、一个公网地址和端口对所有外网主机。
这种情况可以直接使用服务器得到的地址和端口,不过有些NAT需要内网先向某一外网地址发送过数据后,该外网地址才能发送数据进来,所以需要双向打洞。
2、一个公网地址和端口对一个公网地址。
这种情况无法打洞,只能通过服务器转发数据,不过这种NAT所占比例较小。
TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞
原文中的“但NAT-A会纪录此次连接的源地址和端口号,为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了.”这句话不正确!
下次A发送的关于B的IP和端口应该是从server那里得到的!
不然就算你NAT-A记录了但A机是内网机器,怎么可能访问得到NAT-A记录的B机器的IP和端口,;况且我记不记录还有的查证!
<>而且你的这些代码对对称式NAT根本不起作用!
<>只是针对ConeNAPT有效你自己测试一下.ConeNAPT:
对于到同一个IP地址,任意端口的连接分配使用同一个Session;对于到不同的IP地址,任意端口的连接也使用同一个Session.那么对于一个写的优秀的服务器客户端来讲,以下顺序:
直连
UPnP
打洞
转发
无论是TCP还是UDP
UDP"打洞"原理
1. NAT分类
根据Stun协议(RFC3489),NAT大致分为下面四类
1) FullCone
这种NAT内部的机器A连接过外网机器C后,NAT会打开一个端口.然后外网的任何发到这个打开的端口的UDP数据报都可以到达A.不管是不是C发过来的.
例如A:
192.168.8.100NAT:
202.100.100.100C:
292.88.88.88
A(192.168.8.100:
5000)->NAT(202.100.100.100:
8000)->C(292.88.88.88:
2000)
任何发送到NAT(202.100.100.100:
8000)的数据都可以到达A(192.168.8.100:
5000)
2) RestrictedCone
这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口.然后C可以用任何端口和A通信.其他的外网机器不行.
例如A:
192.168.8.100NAT:
202.100.100.100C:
292.88.88.88
A(192.168.8.100:
5000)->NAT(202.100.100.100:
8000)->C(292.88.88.88:
2000)
任何从C发送到NAT(202.100.100.100:
8000)的数据都可以到达A(192.168.8.100:
5000)
3) PortRestrictedCone
这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口.然后C可以用原来的端口和A通信.其他的外网机器不行.
例如A:
192.168.8.100NAT:
202.100.100.100C:
292.88.88.88
A(192.168.8.100:
5000)->NAT(202.100.100.100:
8000)->C(292.88.88.88:
2000)
C(202.88.88.88:
2000)发送到NAT(202.100.100.100:
8000)的数据都可以到达A(192.168.8.100:
5000)
以上三种NAT通称ConeNAT.我们只能用这种NAT进行UDP打洞.
4) Symmetic
对于这种NAT.连接不同的外部目标.原来NAT打开的端口会变化.而ConeNAT不会.虽然可以用端口猜测.但是成功的概率很小.因此放弃这种NAT的UDP打洞.
2. UDPholepunching
对于ConeNAT.要采用UDP打洞.需要一个公网机器C来充当”介绍人”.内网的A,B先分别和C通信.打开各自的NAT端口.C这个时候知道A,B的公网IP:
Port.现在A和B想直接连接.比如A给B发.除非B是FullCone.否则不能通信.反之亦然.但是我们可以这样.
A要连接B.A给B发一个UDP包.同时.A让那个介绍人给B发一个命令,让B同时给A发一个UDP包.这样双方的NAT都会记录对方的IP,然后就会允许互相通信.
3. 同一个NAT后面的情况
如果A,B在同一个NAT后面.如果用上面的技术来进行互连.那么如果NAT支持loopback(就是本地到本地的转换),A,B可以连接,但是比较浪费带宽和NAT.有一种办法是,A,B和介绍人通信的时候,同时把自己的localIP也告诉服务器.A,B通信的时候,同时发localip和公网IP.谁先到就用哪个IP.但是localip就有可能不知道发到什么地方去了.比如A,B在不同的NAT后面但是他们各自的localip段一样.A给B的localIP发的UDP就可能发给自己内部网里面的某某某了.
还有一个办法是服务器来判断A,B是否在一个NAT后面.(网络拓朴不同会不会有问题?
)
http:
//zh.wikipedia.org/wiki/UDP%E6%89%93%E6%B4%9E
在计算机科学中,UDP打洞指的是一种普遍使用的NAT穿越技术。
通过UDP打洞实现NAT穿越是一种在处于使用了NAT的私有网络中的Internet主机之间建立双向UDP连接的方法。
由于NAT的行为是非标准化的,因此它并不能应用于所有类型的NAT。
其基本思想是这样的:
让位于NAT后的两台主机都与处于公共地址空间的、众所周知的第三台服务器相连,然后,一旦NAT设备建立好UDP状态信息就转为直接通信,并寄希望于NAT设备会在分组其实是从另外一个主机传送过来的情况下仍然保持当前状态。
这项技术需要一个圆锥型NAT设备才能够正常工作。
对称型NAT不能使用这项技术。
这项技术在P2P软件和VoIP电话领域被广泛采用。
它是Skype用以绕过防火墙和NAT设备的技术之一。
相同的技术有时还被用于TCP连接——尽管远没有UDP成功。
[编辑]算法
假设有两台分别处于各自的私有网络中的主机:
A和B;N1和N2是两个NAT设备;S是一个使用了一个众所周知的、从全球任何地方都能访问得到的IP地址的公共服务器
步骤一:
A和B分别和S建立UDP连接;NAT设备N1和N2创建UDP转换状态并分配临时的外部端口号
步骤二:
S将这些端口号传回A和B
步骤三:
A和B通过转换好的端口直接联系到对方的NAT设备;NAT设备则利用先前创建的转换状态将分组发往A和B
http:
//zh.wikipedia.org/wiki/NAT%E7%A9%BF%E8%B6%8A
在计算机科学中,NAT穿越(NATtraversal)涉及TCP/IP网络中的一个常见问题,即在处于使用了NAT设备的私有TCP/IP网络中的主机之间建立连接的问题。
会遇到这个问题的通常是那些客户端网络交互应用程序的开发人员,尤其是在对等网络和VoIP领域中。
IPsecVPN客户普遍使用NAT-T来达到使ESP包通过NAT的目的。
尽管有许多穿越NAT的技术,但没有一项是完美的,这是因为NAT的行为是非标准化的。
这些技术中的大多数都要求有一个公共服务器,而且这个服务器使用的是一个众所周知的、从全球任何地方都能访问得到的IP地址。
一些方法仅在建立连接时需要使用这个服务器,而其它的方法则通过这个服务器中继所有的数据——这就引入了带宽开销的问题。
两种常用的NAT穿越技术是:
UDP打洞和STUN。
除此之外,还有TURN,ICE,ALG,以及SBC。
前天编程做了一下UDP打洞的实验,今天特写了一篇文章总结一下。
我们知道网络上两个主机进行通信,如果其中一台主机拥有公网IP那么,那么进行会话是比较简单的,但是如果两台主机是位于不同内网之中的,那么应该如何进行通信呢。
一种想法是再找一台公网的服务器,用来转发信息,但是这有一个问题,就是会给服务器带来压力,因此我们就来谈谈一种用于不同内网中的主机互相通信的一个解决方案——NAT打洞。
原理还是比较简单的,我们先了解一下什么是“NAT的洞”。
当处于内网中的一台主机(ClientA/192.168.1.128)向一个公网的服务器(Server)发送数据时,这时NAT(NAT1)将会打开一个临时性的端口用于与公网的服务器进行通信,并且会把那个内网主机发送出的IP数据报的头部中源IP地址改为NAT的公网IP(218.7.32.28),将TCP或UDP数据报中源端口(2347)改为那个临时端口(26756)这样就实现了由“192.168.1.128:
2347”到“218.7.32.28:
26756”的源地址源端口的转换。
这个数据包到达公网服务器后,服务器就可以根据这个包的头部信息进行回复。
当服务器的数据包到达NAT后,NAT在将这个数据发送到内网主机192.168.1.128的2347端口。
那么这个NAT上的26756端口我们就称作“洞”。
如果这个NAT不是FullConeNAT的话(其实大多数的NAT确实不是这种类型的),那么我们说这个“洞”是有方向性的。
一个洞应该会指向一个(也可以是多个)公网主机的IP地址。
比如上面说的例子,在NAT1上打的洞是指向Server的IP地址。
来自其他公网主机发向这个洞(也就是218.7.32.28:
26756)的数据包会被非FullCone类型的NAT所丢弃。
所以如果有另一台处于另一内网的主机(ClientB/192.168.0.5)向218.7.32.28:
26756直接发送数据的话,同样也会被NAT1丢弃。
那么如何建立ClientA和ClientB的直接会话呢?
网络环境描述:
内网1NAT:
NAT1/218.7.32.28
内网1中一台主机:
ClientA/192.168.1.128
内网2NAT:
NAT2/218.7.31.221
内网2中一台主机:
ClientB/192.168.0.5
公网服务器:
Server
首先让ClientA和ClientB登录到服务器Server(假如两台主机都采用2347端口),此时NAT1和NAT2会分别为ClientA和ClientB打开一个指向Server的洞(NAT1上218.7.32.28:
26756和NAT2上218.7.31.221:
27550)。
服务器应改记录这两个客户端的信息(关键是那两个洞的信息)。
当ClientA与ClientB要建立会话时,ClientA首先用2347端口向NAT2的洞发送一个数据包,当然这个数据包会被