UDP打洞原理介绍

时间:2024-12-12 10:35:14

  
 NAT穿越模块的设计与实现

  Internet的快速发展以及IPv4地址数量的不足使得NAT设备得到了大规模的应用,然而这也给越来越多的端到端通信也带来了不少的麻烦。一般来说,NAT设备允许内网内主机主动向公网内主机发送数据,但却禁止内网外的主机主动向内网内的主机传递数据。由于很多的会话双方处于不同的NAT设备后,它们通信一般通过公网服务器中转,而要建立P2P通信,则必须解决NAT穿越问题才能建立通信。

NAT 是介于内网和公网之间的设备,公网中的IP 地址是全球唯一的,而在内网中的IP 地址可以重复出现,但不能出现在公网中[18]。NAT的基本功能就是通过一个或几个lP地址,来实现局域网上的所有主机都可以对因特网进行访问[19]

NAT实现了公网地址和内网地址之间的映射,可从两个方面来概括:(1) 当内网内的IP包经过NAT需要流入公网时,NAT将此IP 包的源IP地址和端口改为NAT接口上的一个公网地址和端口;(2)当公网中的IP包经过NAT 需要访问内网资源时,NAT将此IP 包的目的地址和端口改为内网IP 地址和端口。

图3.1 UDP包经过NAT原理图

图 3.1是 UDP包经过NAT后的示意图,可以看出UDP包从内网主机A发出时,到达NAT后它的源端IP和端口都已经改变。同时从主机B的UDP包发往NAT-A的公网IP和端口后,NAT将其自动转发给主机A。

3.1 NAT穿越方案分析

3.1.1 NAT的类型

NAT设备的类型对于穿越NAT,有着十分重要的影响,根据其端口映射方式,NAT可分为如下4类,前3种NAT类型可统称为cone NAT。

(1)全克隆( Full Cone) : NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。任何一个外部主机均可通过该映射发送IP包到该内部主机。
    (2)限制性克隆(Restricted Cone) : NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。但是,只有当内部主机先给IP地址为X的外部主机发送IP包,该外部主机才能向该内部主机发送IP包。
    (3)端口限制性克隆( Port Restricted Cone) :端口限制性克隆与限制性克隆类似,只是多了端口号的限制,即只有内部主机先向IP地址为X,端口号为P的外部主机发送1个IP包,该外部主机才能够把源端口号为P的IP包发送给该内部主机。
    (4)对称式NAT ( Symmetric NAT) :这种类型的NAT与上述3种类型的不同,在于当同一内部主机使用相同的端口与不同地址的外部主机进行通信时, NAT对该内部主机的映射会有所不同。对称式NAT不保证所有会话中的内有地址和公开IP之间绑定的一致性。相反,它为每个新的会话分配一个新的端口号。所以即使是同一台外部主机的不同连接,其分配的端口号都是不一样的,通常都是在原来的端口号上加一。

由此可见,Symmetric
Cone条件最严格,Port /Restricted Cone次之,Full Cone条件最不严格。因为我国的网络技术应用得比较晚,所以可以说绝大部分的网络都是cone NAT[20]

3.1.2 NAT给P2P通信带来的问题研究

NAT的存在,使得局域网的用户可以共享一个IP地址访问因特网,解决了IP地址的不足,同时起到了防火墙的作用。但是NAT的存在给P2P网络也带来了问题:(1)内网主机的IP地址是虚拟的,在因特网上是非法的,因而内网主机对公网是不可见的。(2)即使内网内主机的IP地址已知,NAT仍然阻止公网主机主动访问内网主机。(3)内网主机可以作为客户机访问外网,但不能作为服务器向外网提供服务[21]

NAT产生种种问题的原因主要是NAT不允许外部主机主动访问内部主机,这样虽然有安全性高的优点,但是同时带来服务性能低的不良效果。上述这些限制使得在NAT的网络中,外网主机无法穿过NAT主动与内网主机进行通信,P2P网络各主机无法彼此发现对方进行对等信息交换,特别是位于不同NAT之后的不同内网中的机器,更是无法相互连接。如果不能够穿越NAT,P2P网络就无法实现真正的对等,也就无法实现所有信息的交换或共享。

当前处于NAT后的主机通信一般通过服务器的中转,例如当客户机A和客户机B都分别处于不同的NAT后面,先各自发起一个TCP或UDP的连接,连接到一个大家都知道的拥有固定IP地址的服务器S上。由于A和B不能直接连接,两个客户端就使用S服务器进行消息的传递。例如,A要发送一条信息到客户端B,客户端A以C/S连接方式简单的发送一条信息到S服务器,然后S服务器使用已经和客户端B建立的C/S连接发送这条信息到客户端B。NAT后主机不建立P2P通信时发送数据的具体过程如图3.2所示。

这种方法的优势在于只要两个客户端都连在服务器上,它就是有效的。它的明显缺点是它需要了服务器的处理并占用了带宽,而且即使服务器的网络状况良好,也有一定的通讯滞后问题。所以我们需要对该方案进行改进,提出了NAT穿越技术。

图3.2 NAT后主机不建立P2P通信时发送数据的具体过程

NAT穿越的主要目的是是让处于NAT后的通信主机在建立连接后,可以绕过服务器的中转,直接进行P2P通信。这样可以大大节省网络带宽,且数据传输更稳定,出现延时现象更少。

3.1.3 Cone类型的UDP穿越

UDP是是无连接的协议,几乎不提供可靠性措施,但是UDP的效率非常高。它与TCP协议不同,不需要在传输数据之前要建立一种虚拟的连接关系。所以UDP连接只要知道对方的IP地址和UDP端口,就可以进行数据传输。

在P2P网络中,采用UDP方式进行数据传输,只有获得对方主机的公网IP地址和端口才可以进行数据交换。因此,需要在P2P网络中设立一台有公网IP地址的注册服务器,任何主机都要先登录到注册服务器,注册服务器将记录这个IP地址和端口号为公网IP地址和UDP端口。这样在注册服务器上将建立一张映射表,这张映射表记录了登录到注册服务器的主机在内网中的IP地址和端口号和经过NAT之后NAT所分配的IP地址和端口号,即(内网IP地址:UDP端口号)-(公网IP地址:UDP端口号),如果主机不在NAT之后,则二者相同,这样每台登录的主机都拥有Internet上唯一的(公网IP地址:UDP端口号)。

图3.3 UDP穿越示意图

当一台主机要和另一台主机进行通信,它先从注册服务器那里获得目的主机的公网IP地址和端口号,而后就可以直接进行通信,实际的数据交换不需要注册服务器参与,从而实现了P2P穿越NAT。

当主机A1和B1位于不同的NAT之后,它们用UDP穿越NAT建立直接通信如图3.3所示,具体的过程如下:

(1)A1和B1先登录到公网注册服务器,并向服务器发送各自的实际IP地址和UDP端口信息。

(2)注册服务器记录为两个公网IP地址和端口号,同时从接收到的UDP数据报头中提取IP地址和端口信息,记录为内网IP地址和端口号,这样在注册服务器上的映射表中就增加两条记录,分别为:A1:(192.168.1.2:2000)一(10.10.10.10:2000)、B1:(192.168.2.2:4000) 一(20.20.20.20:4000)。

(3)从注册服务器的映射表可以知道A1和B1位于不同的NAT之后。A1要向B1发送UDP消息那么A1发送命令给Server,请求Server命令B1向A1方向打洞, Server在发送打洞命令时同时将Client A的公网地址10.10.10.10:2000发送给B1(20.20.20.20:4000)。B1收到命令后向A1的公网地址10.10.10.10:2000发送信息,虽然NAT A会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。但是我们已经在NAT B上打一个方向为20.20.20.20:4000(即 A1的外网地址)的洞,那么A1发送到20.20.20.20:4000的信息, B1就能收到了。然后 A1就可以通过B1的外网地址与B1进行P2P通信了。

(4)至此,两个不同NAT之后的主机A1和B1穿越NAT之后,实现了P2P的信息直连。

3.1.4 cone类型的TCP穿越

对于UDP穿越NAT,现在已经有了一些比较标准而且有效的方法,如STUN协议。但目前尚未能完全解决TCP穿越NAT的问题,即便有一些方法,但也处于测试阶段。在此介绍一下当前一种TCP穿越实现方法,其原理是呼叫双方处于不同的NAT后,处于NAT后的主机先与公网上的注册服务器建立辅助连接( TCP、UDP均可) ,在呼叫发生时,通过注册服务器的协助在呼叫双方间建立TCP直连。

对于cone类型的NAT可采用图3.4所示的方法解决TCP穿越问题,主要过程可分为建立辅助连接、查询被叫、TCP打孔、建立TCP直连4个部分。

3.1 建立辅助连接

各会话用户先与注册服务器建立UDP连接(以下称为辅助通道)并一直在该连接通道上发送UDP数据包以保持自己处于激活状态,服务器记录各用户的ID (ID是用户的唯一标识符)。

图3.4 “TCP打孔”方法穿越NAT过程

(注:图中圆括号内为消息内容,方括号内为消息路径。如连接通知(C: V)UDP[ C: R >NB: Q >B: P ]表示该消息内容为服务器地址、端口(C: V) ,消息从IP地址C端口R出发经过IP地址NB端口Q到达IP地址B端口P。)

3.2 查询被叫

(1)主叫A与呼叫服务器C建立TCP连接,并向服务器发送被叫ID,请求服务器协助查询被叫IP地址、端口。服务器记录主叫在经NAT映射前后的IP地址、端口(NA:N)以及本次连接使用的端口V。该请求在建立TCP直连的步骤3中得到回复。

(2)呼叫服务器通过已经建立的辅助通道向被叫发送连接通知,其中携带与主叫建立TCP连接使用的IP地址、端口(C:V),即通知被叫向该地址、端口回送消息。

(3)被叫向连接服务器回复连接请求,建立TCP连接,服务器记录被叫在经NAT映射前后的IP地址、端口(NB:Y)。

3.3 TCP打孔

(1)连接服务器向被叫返回连接的详细信息,如主叫ID及主叫经过NAT映射后的IP地址、端口(NA:N) ,并关闭与被叫的TCP连接;

(2)被叫尝试向主叫的经过NAT映射后的IP地址、端口(NA:N)发送建立TCP连接的请求。

(3)根据前述的NAT类型,此处可能有2种情况: 1) Full
Cone方式下,NATA会将该TCP消息转发到内网内的主叫端口M,由于主叫A 已经使用该端口与连接服务器建立TCP连接,故主叫A会返回一个端口已占用消息; 2)Restricted Cone 或Port Restricted Cone方式下,NAT A不会转发该消息给主叫, 而是返回一条出错消息给被叫。如果NAT B收到该出错消息后,将其转发给内网内的被叫B,则该TCP连接终止, TCP打孔失败。但绝大多数情况下,NATB不会将上述2种出错消息转发内网内的主机,从而完成TCP打孔。

3.4 建立TCP直连

(1)被叫B在端口X启动TCP监听,并使用与上述不同的端口G与服务器建立TCP连接,以及通知服务器被叫已完成TCP打孔和做好TCP直连准备。

(2)服务器向主叫A 发送被叫(B:X) 经NAT映射后的IP地址、端口(NB:Y),并关闭和主叫建立的TCP连接。

(3)主叫(A:M)向上述IP地址、端口(NB:Y)发送TCP连接请求,即可与被叫B成功建立TCP直连。

3.1.5 Symmetric Cone 的UDP穿越

对于cone 类型NAT,由于每次会话其端口是固定的,客户机可以通过注册服务器间接获取其公网的映射IP和端口,从而可以建立连接。而对于Symmetric类型NAT,当主机B向主机A打洞时的其会话端口已经重新分配了,主机 B将无法知道这个端口,客户机之间就无法建立连接。

由于Symmetric NAT映射新的端口的方式主要有三种:一是在前一次映射的端口号上加1(或增加一个固定的整数T,T>1);二是在前一次映射的端口号上增加或减少,且变化的数值随机在一个小范围内生成;三是在区间 (1024,65535) 随机生成。其中第一种映射方式最为常见,然后依次是第二和第三种的。如果可以猜测UDP端口,则建立连接的可能性就可以实现。

当前有研究人员提出一种基于端口映射方式有规律性的准随机猜测方法来猜测UDP端口,该算法设计首先要判断目标方NAT的映射方式,让发起访问的客户端(比如 A)向服务器 S查询最近3次注册的、相继被映射成和目标客户端(比如B)同一全局地址(比如202.1.1.1)的B方客户端的端口号,若其值递增且最后一次注册的客户端的端口号(记为P0)最大,则【判定1】Symmetric NAT最有可能是第一种映射方式,亦有可能是第二或第三种映射方式;如果最近一次注册的端口号不是最大,则【判定2】Symmetric NAT一定是第二或第三种映射方式。一种极端情况,当前B方内网主机包括B在内向S注册的映射为地址202.1.1.1的共不到3台,若只有B注册,则当成【判定1】的情形处理;若有2台注册,仍按后一次映射的端口号是否更大而判断其映射方式。

在对端口测试过程中,需要对端口猜中与否的判断:假设A和B相互发送报文时,NAT映射后各自的全局插口为[IPa:Pa]和[IPb:Pb]。若A发送的猜询报文目标端口变为Pb,即先猜中了B的端口,B的NAT仍会丢弃A的这个报文。但这时在A方建立了会话[IPa:Pa , IPb:Pb];在此会话的生存期内,若B也猜中了A的端口Pa,则B的猜询报文就能发送到A并收到A的响应报文,A则收到B的猜询报文。即任意一方收到猜询报文或响应报文就表明双方都已猜中对方端口。若A 先猜中B的端口,而在该会话的生存期内B没有猜中A的,则A并不知道自己已经猜中故会继续对B发送猜询报文。

3.1.6 NAT穿越方案分析

对于对称式NAT,需要先经过地址探测技术的协助来完成穿越[22] 。近期研究表明,市场上对称式NAT应用很少,而且NAT由于意识到其对端到端通信会带来较大障碍,因此正在力图减少使用对称式的映射方式。考虑到当前应用的NAT绝大多数都是Cone类型的,这满足后期双向透明转换模块的产品化的市场化需要,所以选择了Cone类型的NAT作为穿越目标。当前UDP穿越NAT技术已经比较成熟,并有了标准,而TCP穿越NAT虽然有成功实验的,但相对来说不稳定。考虑到本课题是基于应用目的,对系统要求稳定,同时由于网络数据量也较小,UDP已经可以满足要求。通过比较,选用UDP穿越Cone类型的NAT穿越实现处于NAT后的串口设备建立P2P通信功能。

3.2 心跳包的分析与设计

3.2.1 心跳包的分析

UDP是无连接的协议,NAT对UDP传输的映射是动态的,也就是说经过一段时间之后,如果NAT后的内网主机不再发送或接收数据,映射后的IP地址和端口号会发生改变,映射关系会自动解除,分配的UDP端口号会被NAT收回,重新分配给其他连接。这样在注册服务器上的映射表就会变得无效,主机也就不能为其他主机所识别,所以必须保持NAT的映射关系不会动态改变。

为了保持NAT对UDP的映射不变,NAT后的主机可以定时向NAT发送保持映射的UDP消息,保证NAT为相应主机分配的UDP端口不被收回。发送的目的地址是该主机登录注册服务器时,NAT为它分配的Internet合法IP地址和相应的UDP端口。由于UDP的无连接性,任何主机发送到该Internet合法IP地址和UDP端口的消息,经过NAT后消息都将被相应的内网主机所接收到,所以此时相当于主机本身向自己发送了一条UDP消息,主机接收到这样的消息后直接丢弃,这样映射关系就能够保持。

3.2.2 心跳包的设计

在完成UDP穿越过程中,心跳包的是设计一个必不可少的环节。按照理论,NAT将在一定时间后关闭UDP的一个映射,所以为了保持与对方能够一直通信,主机必须要发送UDP心跳包,来保持映射不被关闭。心跳包内容可以自己定,也可以是个空数据包。在本设计中使用了二个定时器来完成发送心跳包,初始化时关闭第二个定时器,第一个定时器负责向服务器发送心跳包,维持与服务器的连接;在收到打洞命令后,关闭第一个定时器,停止向服务器发送心跳包,使能第二个定时器,由它负责向P2P的对方主机发送心跳包。

心跳包的发送间隔时间也需要注意,间隔时间太长,映射关系将被关闭,不能起到心跳包的作用。间隔时间太短,发送数据太多将占用大量的网络带宽,同时浪费资源。在本设计中,经过大量测试,心跳包的发送间隔时间为20秒较为合适。