Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1520349
  • 博文数量: 114
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 1357
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-19 18:13
文章分类
文章存档

2010年(8)

2009年(9)

2008年(27)

2007年(62)

2006年(8)

我的朋友

分类: LINUX

2008-01-29 22:46:50

北京理工大学  20981  陈罡
 
继续上一篇的。。。
 
3 UDP打洞方式
 
即使两个p2p客户端都位于NAT设备后面,UDP打洞方式也能够通过已知的服务器实现p2p客户端直连。
该技术在RFC 3027的第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.3 p2p客户端位于同一个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.4 p2p客户端位于不同的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-->
本地IP:10.1.1.3,本地端口:4321,公网IP: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发过来的消息是未经授权的公网消息,会丢弃掉该数据包。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数据传输。
 
未完待续。。。
阅读(2349) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~