穿越NAT的p2p通信方法研究Word文档下载推荐.docx
- 文档编号:20260663
- 上传时间:2023-01-21
- 格式:DOCX
- 页数:14
- 大小:200.25KB
穿越NAT的p2p通信方法研究Word文档下载推荐.docx
《穿越NAT的p2p通信方法研究Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《穿越NAT的p2p通信方法研究Word文档下载推荐.docx(14页珍藏版)》请在冰豆网上搜索。
很显然,我们需要一种方法即使在NAT设备存在的前提下,仍然能够无障碍地实现p2p通信。
在不同内网的两个节点之间建立p2p连接的最有效的方法就是“打洞”。
该技术在基于UDP的应用程序中得到了广泛的应用,同样的,该技术也可以用于基于TCP的应用程序。
有趣的是,与“打洞”字面上的意思刚好相反,该技术不会影响到内网的安全。
事实上,“打洞”技术使得p2p软件的绝大部分功能都在NAT设备默认的安全策略的控制之下,这些都由NAT设备建立的session来管理。
本文阐述了适用于UDP和TCP的“打洞”技术,并详细描述了重要“打洞”过程中,应用程序和NAT设备之间的行为。
不幸的是,由于NAT设备的响应和行为不是标准的,所以没有任何技术可以穿越现有的所有NAT设备。
本文提供了一些在现有NAT设备上进行“打洞”的实验结果。
我们收集的数据来自于互联网上使用了“NATCheck”工具并在大量不同生产厂商的NAT设备上进行“打洞”实验的用户。
由于数据是来自于一个叫做“self-selecting”的用户社区,或许不会完全代表在Internet上真正部署和使用的NAT设备,但是结果无论如何还是很令人兴奋的。
在做基本的“打洞”操作评估的时候,我们应该指出在现有的NAT设备“打洞”的复杂度上,不同的复杂度会有不同的结果。
但目前我们把讨论的重点集中于开发最简单的,可以应用于任何网络拓扑结构的、稳定的、有正确NAT响应的NAT设备上的“打洞”技术。
我们有意避免使用一些“聪明的小把戏”通过欺骗某些NAT设备来达到短期内穿越较多的NAT设备,但从长期来看会引起网络未知错误的技术。
尽管引入IPv6会极大地增加互联网的地址空间,从而减少对于NAT设备的需求量,但短期内IPv6确实增加了对NAT设备的需求量,因为NAT设备本身提供了一种方便的方法进行IPv4与IPv6地址域转换。
另外私有网络上建立匿名和加密访问节点也有利于组织机构的安全性以及不受外界干扰,这些都意味着NAT还将存在相当长的一段时间。
同样,防火墙技术也不会由于有了足够的ip地址而消失,IPv6的防火墙仍然会默认丢掉所有XX的数据包,仍然可以让在IPv6环境下工作的应用程序“打洞”。
本文接下来的部分按照如下的方式组织:
第二章介绍基本的NAT穿越概念和术语;
第三章介绍UDP“打洞”过程;
第四章介绍TCP“打洞”过程;
第五章介绍支持“打洞”的NAT设备必须具有那些特性;
第六章介绍我们在目前流行的NAT设备上的“打洞”实验结果;
第七章讨论相关的网络问题;
第八章全文总结以及结束语。
2、基本概念本节介绍了本文使用到的基本的NAT术语,着重描述了适用于UDP和TCP两种协议的通用的NAT穿越技术。
2.1、NAT术语
本文绝大部分术语和分类来自于RFC2663定义,另外一些来自于较新的RFC3489中的定义。
理解session是很重要的。
一个TCP或UDP的sessionendpoint是由一个IP地址,端口号组成,每个session是由两个sessionendpoint构成。
从内网节点的角度来看,一个session由4部分组成分别为:
本地IP,本地端口,远端IP,远端端口。
session的方向通常代表了数据包的初始流动的方向;
对于TCP来说就是SYN包的流向,对于UDP来说就是第一个用户数据包的流向。
NAT有很多种,但最普遍的一种类型叫做“传统”NAT,或者“向外”NAT。
他们在内网和公网之间提供了一个“不对称”桥的映射。
“向外”NAT在默认情况下只允许向外的session穿越NAT:
从外向内的的数据包都会被丢弃掉,除非NAT设备事先已经定义了这些从外向内的数据包是已存在的内网session的一部分。
“外向”NAT会造成p2p协议的混乱,因为当p2p的双方决定向在不同NAT后面的对方开始通信的时候,无论哪一方试图初始化一个session,另一方的NAT都会拒绝这个请求。
NAT穿越的核心思想就是让p2p的双方的NAT看上去都是“向外”的NAT。
“向外”NAT有两种类型:
(1)“基础”NAT,该NAT只转换IP地址,不转换端口号。
(2)NAPT(NetworkAddress/PortTranslation)NAPT转换整个sessionendpoints。
由于NAPT允许内网的多个节点通过共享的方式使用同一个的公共的IP地址,因此,支持NAPT的NAT设备才会越来越多。
尽管本文通篇讨论的内容都是基于支持NAPT的NAT设备的,但这些规律和技术同样适用于“基础”NAT。
2.2转发方式
最可靠但同时也是效率最低的p2p穿越NAT进行通信的方法是采用类似C/S方式的转发。
假定两个节点A和B每个节点都有向外的TCP或UDP连接,联入公共的已知服务器S,S的公网IP地址是18.181.0.31,端口号是1234(如图2所示),每个客户端位于不同的私有内网中,并且它们的NAT设备妨碍了客户端之间直接的p2p连接。
做为对直连方案的替代方案,两个客户端可以利用公共的服务器S进行消息的转发。
例如,A为了将消息送给B,A只需将消息发给S,然后由S转发给B,这一过程将使用A与B事先与S建立好的连接。
转发方式通常只能在双方客户端都连接到服务器的时候有效。
这种方式的缺点在于,它假定服务器的处理能力和网络带宽以及通信延迟都是理想的情况下,不会受到客户端个数的影响。
但是,由于没有其它的方法能够像转发方式那样,可以穿越现存的所有NAT设备,因此在构建高可靠性的p2p系统的时候,通过服务器转发的方式依旧是一个非常有用的保证系统可靠性的方法。
TURN协议定义了如何实现安全的转发方式。
2.3反向连接方式
一些p2p的应用程序采用了直接但是有所限制的技术来实现NAT穿越,该技术叫做“反向连接”,这是用于当两个节点联入服务器S的时候,只有一个一个节点在NAT设备的后面(如图3所示)。
如果A希望建立与B的连接,那么A可以直接联入B,因为B是在公网中存在的,没有经过NAT转换,而且A的NAT设备也允许A直接由内网发起向外网的连接。
如果B希望建立与A的连接,很不幸,A的NAT设备会阻止该操作,此时,B可以借助于转发服务器S,向A发送“反向连接”请求,由A“主动”连接B,从而达到A与B的p2p通信的目的。
尽管该技术的局限性非常明显,但是使用已知的服务器做为中介辅助p2p客户端双方进行p2p连接的思想已经成为了更加通用的“打洞”技术的基本思想。
3UDP打洞方式
即使两个p2p客户端都位于NAT设备后面,UDP打洞方式也能够通过已知的服务器实现p2p客户端直连。
该技术在RFC3027的第5.1节中曾有所提及,在网络上可以找到对其较模糊的描述,在最近的IP协议实验中得到应用,在多种在线游戏协议中得到了应用。
3.1集中服务器
打洞技术假定客户端A和B可以与公网内的已知的集中服务器建立UDP连接(可以互发UDP数据包)。
当一个客户端在S上登陆的时候,服务器记录下该客户端的两个endpoints(IP地址,UDP端口),一个是该客户端确信自己是通过该ip和端口与服务器S进行通信的,另一个是服务器S记录下的由服务器“观察”到的该客户端实际与自己通信所使用的ip和端口。
我们可以把前一个endpoint看作是客户端的内网ip和端口,把后一个endpoint看作是客户端的内网ip和端口经过NAT转换后的公网ip和端口。
服务器可以从客户端的登陆消息的消息体中得到该客户端的内网endpoint相关信息,可以通过对登陆消息的IP或UDP头得到该客户端的公网endpoint。
如果该客户端不是位于NAT设备后面,那么采用上述方法得到的两个endpoint的值应该完全相同。
也有一些“弱智”的NAT设备会扫描UDP数据包的包体,寻找4字节的位域,看上去很像IP地址的位域,并且把它们改为与IP头一样的地址。
为了避免这种行为的NAT设备对UDP数据包包体的修改,应用程序可以采用直接对IP地址的值进行加密的方式骗过NAT设备的检查。
3.2建立p2p的session
假定A要发起对B的直接连接,“打洞”过程如下所示:
(endpoint指ip地址和端口的配对)
(1)A最初不知道如何向B发起连接,于是A向服务器S发送消息,请求S帮助建立与B的UDP连接。
(2)S将含有B的公网和内网的endpoint发给A,同时,S将含有A的公网和内网的endpoint的用于请求连接的消息也发给B。
一旦这些消息顺利到达,A与B就都知道了对方的公网和内网的endpoint。
(3)当A收到由S发来的包含B的公网和内网endpoint的消息,A开始向这些B的endpoint发送UDP数据包,并且A会自动锁定第一个给出响应的B的endpoint。
同理,当B收到由S发来的A的公网和内网endpoint以后,也会开始向A的公网和内网的endpoint发送UDP数据包,并且自动锁定第一个得到A的回应的endpoint。
由于A与B的互相向对方发送UDP数据包的操作是异步的,所以A和B发送数据包的时间先后并没有严格的时序要求。
下面我们就来看一下这三个角色之间是如何进行UDP“打洞”的。
在这里我们分为三种具体情景来讨论:
第一种也是最“简单”的一种情景,两个客户端都位于同一个NAT设备后面,位于同一个内网中;
第二种也是最普遍的一种情景,两个客户端分别位于不同的NAT设备后面,分属不同的内网;
第三种是客户端位于两层NAT设备之后,通常最上层的NAT是由ISP网络提供商,第二层的NAT是家用的NAT路由器之类的设备。
通常情况下由应用程序自身确定的网络物理层连接方式是很困难的,有时甚至是不可能的,即使是上述的若干种情景下可以穿越NAT,也只是代表在一定时期内有效,而不是永久有效的。
诸如STUN之类的网络协议或许可以提供必要的NAT信息,但在遇到多层NAT设备的时候,通常这些信息也不是完全完整和有效的。
尽管如此,只要NAT设备的响应是“合理”的,在通常情况下“打洞”技术还是能够在应用程序对网络状况一无所知的前提下自动适用于多数场合。
(“合理”的NAT响应将在第五章中详细讨论)
3.3p2p客户端位于同一个NAT设备后面
首先假设两个客户端位于同一个NAT设备后面,并且位于相同的内网(相同的私有IP地址域)如图4所示。
A与S建立了UDP连接,经过NAT转换后,A的公网端口被映射为62000。
B同样与S建立了UDP连接,公网端口映射为62005。
(图4)
假设A想通过服务器S做为介绍人,发起对B的连接。
A向S发出消息请求与B进行连接。
S将B的公网endpoint(即公网ip和port)以及内网endpoint(即内网ip和port)发给A,同时把A的公网、内网的endpoints发给B。
由A和B发往对方公网endpoint的UDP数据包能否被对方收到,这取决于当前的NAT是否支持“发夹”转换(hairpin转换,也就是同一台设备,不同端口之间的UDP数据包能否到达,详见3.5节)。
但是A与B往对方内网endpoint发送的UDP数据包是一定可以到达的,无论如何,内网数据包不需要路由,并且速度更快。
A与B有很大的可能性采用内网的endpoint进行常规的p2p通信。
假定NAT设备支持“发夹”转换,应用程序也忽略由内网endpoint的连接,那么A、B会采用公网endpoint做为p2p通信的连接,这势必会造成数据包无谓地经过NAT设备,这是一种对资源的浪费。
我们会在第六节讨论这种情况,毕竟支持“发夹”转换的NAT设备还远没有对“打洞”技术支持的NAT设备多。
就目前的网络情况而言,应用程序在“打洞”的时候,最好还是把公网endpoint和内网endpoint都实验一下。
3.4p2p客户端位于不同的NAT设备后面
假定A与B在不同的NAT设备后面,分属不同的内网,如图5所示。
A与B都经由各自的NAT设备与服务器S建立了UDP连接,A与B的本地端口号均为4321,服务器S的公网端口号为1234。
在“向外”session中,A的公网IP被映射为155.99.25.11,公网端口为62000,B的公网IP被映射为138.76.29.7,公网端口为31000。
如下所示:
客户端A-->
本地IP:
10.0.0.1,本地端口:
4321,公网IP:
155.99.25.11,公网端口:
62000客户端B-->
10.1.1.3,本地端口:
138.76.29.7,公网端口:
31000
(图5)
在A向服务器S发送的登陆消息体中,会包含A的内网endpoint信息,即10.0.0.1:
4321;
服务器S会记录下A的内网endpoint,同时会把自己观察到的A的公网endpoint记录下来,即155.99.25.11:
62000。
同理,服务器S会记录下B的内网endpoint,10.1.1.3:
4321和由S观察到的B的公网endpoint,138.76.29.7:
31000。
无论A与B二者任何一方向S发送p2p连接请求,服务器都会将其记录下来的上述的公网、内网endpoint发送给A、B。
由于A、B分属不同的内网,它们彼此的内网endpoint无法在公网中路由,所以发往各自内网endpoint的UDP数据包会发送到错误的主机或者根本不存在的主机。
因此应用程序对于收到的消息必须经过授权和过滤,只有通过授权的的消息才能是从对方的endpoint发出来的,例如,可以在消息中加入对方的程序名称、加密算法,或者至少是一个双方都从服务器S上的预先得到的随机数字。
现在假定A的第一个消息将发往B的公网endpoint,如图5所示。
该消息途经A的NAT设备,并在该设备上生成了一个“向外”的session。
新的session源endpoint是10.0.0.1:
4321该endpoint和A与服务器S的建立连接的时候NAT生成的源endpoint一样,但它的目的endpoint不同。
如果A的NAT设备给出的响应是“友好”的,那么A的NAT设备将保留A的内网endpoint,并且所有来自A的源endpoint(10.0.0.1:
4321)的数据包都沿用A与S事先建立起来的session,公网endpoint均为(155.99.25.11:
62000)。
A向B的公网endpoint发送消息的过程就是“打洞”的过程,从A的内网的角度来看应为从(10.0.0.1:
4321)发往(138.76.29.7:
31000),从A的在其NAT设备上建立的session来看,是从(155.99.25.11:
62000)发到(138.76.29.7:
31000)。
如果A发给B的公网endpoint的消息包在B向A发送消息包之前到达B的NAT设备,B的NAT会认为A发过来的消息是XX的公网消息,会丢弃掉该数据包。
B发往A的消息包根上述的过程一样,会在B的NAT上建立一个(10.1.1.3:
4321,155.99.25.11:
62000)的session(通常也会沿用B与S连接时建立的session,只是该session现在不光可以接受由S发给B的消息,还可以接受从A的NAT设备-155.99.25.11:
6200发来的消息)
一旦A与B都向对方的NAT在公网上的endpoint发送了数据包,就打开了A与B之间的“洞”,A与B向对方的公网endpoint发送数据,等效为向对方的客户端直接发送UDP数据包了。
一旦应用程序确认已经可以通过往对方的公网endpoint发送数据包的方式让数据包到达NAT后面的目的应用程序,程序会自动停止继续发送用于“打洞”的数据包,转而开始真正的p2p数据传输。
3.5p2p客户端位于多层NAT设备后面
有的网络拓扑结构包含了多个NAT设备,如果没有掌握该拓扑结构的详细信息,两个客户端之间是无法建立“最优化”的p2p路由的。
现在我们来讨论最后一种情况,如图6所示。
假定NATC是由ISP(InternetServiceProvider)提供的工业级的NAT设备,NATC提供将多个下属的用户NAT或用户节点映射到有限的几个公网IP的服务,NATA和NATB做为NATC的内网节点将把用户的家庭网络或内部网络接入NATC的内网,然后用户的内部网络就可以经由NATC访问公网了。
从这种拓扑结构上来看,只有服务器S与NATC是真正拥有公网可路由IP地址的设备,而NATA和NATB所使用的“公网”IP地址,实际上是由ISP服务提供商设定的(相对于NATC而言)内网地址(本位的后续部分我把这个由ISP提供的内网地址相对于NATA和NATB称之为“伪”公网地址),同理隶属于NATA与NATB的客户端,相对与NATA,NATB而言,它们处于NATA,NATB的内网,以此类推,客户端可以放到到多层NAT设备后面。
客户端A和客户端B发起对服务器S的连接的时候,就会依次在NATA和NATB上建立向外的session,而NATA、NATB要联入公网的时候,会在NATC上再建立向外的session。
(图6)
现在假定客户端A和B希望通过UDP“打洞”完成两个客户端的p2p直连。
最优化的路由策略是客户端A向客户端B的“伪公网”IP上发送数据包,即ISP服务提供商指定的内网IP,NATB的“伪”公网endpoint,10.0.1.2:
55000。
由于从服务器S的角度只能观察到真正的公网地址,也就是NATA,NATB在NATC建立的session的真正的公网地址155.99.25.11:
62000以及155.99.25.11:
62005,所以非常不幸,客户端A与客户端B是无法通过服务器S知道这些“伪”公网的地址的。
而且即使客户端A和B通过某种手段可以得到NATA和NATB的“伪”公网地址,我们仍然不建议采用上述的“最优化”的打洞方式,这是因为这些地址是由ISP服务提供商提供的或许会存在与客户端本身所在的内网地址重复的可能性。
(例如:
NATA的内网的IP地址域恰好与NATA在NATC的“伪”公网IP地址域重复,这样就会导致打洞数据包无法发出的问题)
因此客户端别无选择,只能使用由公网服务器S观察到的A,B的公网endpoint进行“打洞”操作,用于“打洞”的数据包将由NATC进行转发,这里NATC是否支持“发夹”转换或“环路”转换非常重要,否则数据包将无法由NATC转发给NATA和NATB,进而无法到达客户端A和B。
当客户端A向客户端B的公网endpoint(155.99.25.11:
62005)发送UDP数据包的时候,NATA首先把数据包的源endpoint由A的内网endpoint(10.0.0.1:
4321)转换为“伪”公网endpoint(10.0.1.1:
45000),现在数据包到了NATC,NATC应该可以识别出来该数据包是要发往自身转换过的公网endpoint,如果NATC可以给出“合理”响应的话,NATC将把该数据包的源endpoint改为155.99.25.11:
62000,目的endpoint改为10.0.1.2:
55000,即NATB的“伪”公网endpoint,NATB最后会将收到的数据包发往客户端B。
同样,由B发往A的数据包也会经过类似的过程。
也有很多NAT设备不支持类似这样的“发夹”转换,但是已经有越来越多的NAT设备生产厂商开始加入对该转换的支持。
3.6UDP在空闲状态下的超时问题
由于UDP转换协议提供的“洞”不是绝对可靠的,多数NAT设备内部都有一个UDP转换的空闲状态计时器,如果在一段时间内没有UDP数据通信,NAT设备会关掉由“打洞”操作打出来的“洞”,做为应用程序来讲如果想要做到与设备无关,就最好在穿越NAT的以后设定一个穿越的有效期。
很遗憾目前没有标准有效期,这个有效期与NAT设备内部的配置有关,最短的只有20秒左右。
在这个有效期内,即使没有p2p数据包需要传输,应用程序为了维持该“洞”可以正常工作,也必须向对方发送“打洞”维持包。
这个维持包是需要双方应用都发送的,只有一方发送不会维持另一方的session正常工作。
除了频繁发送“打洞”维持包以外,还有一个方法就是在当前的“洞”有效期过期之前,p2p客户端双方重新“打洞”,丢弃原有的“洞”,这也不失为一个有效的方法。
4关于TCP打洞技术
建立穿越
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 穿越 NAT p2p 通信 方法 研究