NAT内网穿透-很不错的文章

Home / Article MrLee 2019-3-20 1648

qq早期在线聊天使用udp实现的且是P2P的,其中一点优势就是P2P的udp的穿墙优势,其他包括效率高,占用资源少,速度快,但是其传输机制为不可靠传输,必须依靠辅助算法来完成传输控制。

https://blog.csdn.net/unknow_cdc/article/details/77825232

利用P2P点对点技术实现,需解决的两个问题。 
1.实现内网之间机器的网络通信。 
2.需要解决UDP出现的数据传输不稳定问题。

NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task Force, Internet工程任务组)标准,允许一个整体机构以一个公用IP(Internet Protocol)地址出现在Internet上。顾名思义,它是一种把内部私有网络地址(IP地址)翻译成合法网络IP地址的技术。

NAT三种实现方式

静态地址转换:一个公网IP对应一个内部IP,一对一转换

动态地址转换:N个公网IP对应M个内部Ip,不固定的一对一IP转换关系.同一时间,有M-N个主机无法联网.

端口多路复用:对外只有一个公网IP,通过端口来区别不同内部IP主机的数据.

IP转换策略

对于静态与动态地址转换;其数据包出站的时候,进行源地址转换.我们称之为SNAT[SOURCE ADDRESS].其内部源IP变公网源IP.数据包入站的时候,进行目标地址转换DNAT[DESTINATION ADDRESS],其外部公网宿IP变内部宿IP.静态与动态不进行端口转换.而端口多路复用技术.不但要转换其IP地址,还要进行其传输层的端口转换.通过这唯一的端口号来区别不同的内部数据[在通信过程中会建立一张内部到外部映射表].我们称之NATP[NAT PORT]技术.在我们家用网络中,大部分用的是端口多路复用技术.在端口多路复用技术中,对数据的处理还分这么两类:锥形NAT与对称型NAT.锥形NAT又分完全锥形NAT[FULL CONE]|受限锥形NAT[RESTRICTED CONE]|端口受限锥形NAT[PORT RESTRICTED CONE].

全完锥形NAT:将来自内部同一个IP地址同一个端口号的主机监听/请求,映射到公网IP某个端口的监听.任意外部IP地址与端口对其自己公网的IP这个映射后的端口访问,都将重新定位到内部这个主机.个人认为在内部发布服务器到外网,此技术原理完全否合该技术原理,当然某些P2P中也可能利用该技术.该技术中,基于C/S架构的应用可以在任何一端发起连接.

受限锥形NAT:与完全NAT不同的是,在公网映射端口后,并不允许所有IP进行对于该端口的访问,要想通信必需内部主机对某个外部IP主机发起过连接,然后这个外部IP主机就可以与该内部主机通信了.但端口不做限制.如出站源IP为A端口为B,对于外部IP回复,宿IP为A宿端口可以是任意.NAPT设备都将成功转发到内部主机.NAPT设备根据映射记录做出判断.该技术中只能内部主机先发起连接通信才可成功.

端口受限锥形NAT:该技术与受限锥形NAT相比更为严格.除具有受限锥形NAT特性.对于回复主机的源端口也有要求.哪我用端口B访问你,对于外部主机的回复信宿端口也只能是B.否折通信失败.该技术中只能内部主机先发起连接通信才可成功.

对称型NAT:内部主机用同一IP与同一端口与外部多IP通信.NAPT设备为每个会话转换了不同的源端口.不在转换成相同的源端口.对于回复的数据包,只有信宿IP地址与端口完全吻合才可进入.当然源IP也是要检测的,不可能随意外部IP都能进入的.

参考文献: 
http://blog.csdn.net/fazhunchan/article/details/5394608 
http://www.cnblogs.com/bo083/articles/2170189.html 
http://blog.csdn.net/ustcgy/article/details/5652268

转发

最可靠但又是最低效的点对点通信方法,莫过于将p2p网络通信看作一个C/S结构,通过服务器来转发信息.如下图,两个客户端A和B,均与服务器S初始化了一个TCP或UDP连接,服务器S具有公网固定IP地址,两个客户端分布在不同的私网中,这样,他们各自的NAT代理服务器将不允许他们进行直连.

123456789

取而代之的方式是,两个客户端可以把服务器S当作信使来转发消息.比如,为了将消息发送到B,A先发送一条信息给服务器S,服务器S再利用初始化时已经建立的连接,将信息转发给B. 

NAT211.133.和NAT211.134.之间需要进行通信,但开始不能直接就发数据包,我们需要一个中间人,这个就是外部索引服务器(我们假设是211.135.:7000),当NAT211.133.向211.135.:7000发送数据包,211.135.:7000是可以正常接收到数据,因为它是属于对外型开放的服务端口。当211.135.:7000收到数据包后可以获知NAT211.133.对外通信的临时SESSION信息(这个临时的端口,假设是6000会过期,具体的时间不同,但我个人的测试是每30秒发送一个心跳包keep住连接以保证端口维持住通信连接不断开),索引服务器此时应将此信息保存起来。而同时,NAT211.134.也在时刻向索引服务器发送心跳包,索引服务器就向NAT211.134.发送一个通知,让它向NAT211.133.:6000发送探测包(这个数据包最好多发几个),NAT211.134.在收到通知包之后再向索引服务器发送反馈包,说明自己已经向NAT211.133.:6000发送了探测包,索引服务器在接收到反馈包之后再向NAT211.133.转发反馈包,NAT211.133.在接收到数据包之后再向原本要请求的NAT211.134.发送数据包,此时连接已经打通,实现穿透,NAT211.134.*会将信息转发给192.168.1.88的9000端口。

此处输入图片的描述

这个方法的优势是:它适合于任何NAT包括Symmetric NAT.但是它的劣势也很明显:它将全面依赖并消耗服务器的资源和网络带宽.名为 TURN 的协议定义了一个利用转发技术进行可靠通信的模型. 

反向连接

这里介绍第二种技术,但是它只能在通信的两端只有一端处于NAT之后的情况下.举例来说,假设客户端A处于NAT之后,而客户端B有一个公网IP地址,如下图所示. 

123456789101112

现在我们假设客户端B将会与客户端A初始化一个端对端连接会话.B将首先试图连接A的一个地址—客户端A认为是它自己的地址10.0.0.1:1234或者是从服务器S观察到的地址155.99.25.11:62000.然而不论是连接哪一个,都不可能成功.第一种情况:试图直接连到10.0.0.1肯定会失败,因为10.0.0.1根本就不是一个可以在公网上路由的IP地址;第二种情况,从B传来的请求将能够到达端口NAT A的端口62000,但NAT A却会拒绝这个连接请求,因为只有外出的连接才允许进入. 在所有的尝试都失败之后,客户端B就只能通过服务器S来请求A做一个”反向”连接到客户端B,客户端A将打开一个与客户端B通讯的连接(在B的公网IP地址和端口号上).NAT A允许这个连接通过,因为这个连接起源于NAT A的内部,并且同时客户端B能够受这个连接因为B并不位于NAT之后. 

这个方法的优势是:它也适合于任何NAT包括Symmetric NAT.它的主要限制在于,只能有一端位于NAT之后.

UDP打洞

第三种技术,也是这篇文章主要要介绍的,就是非常有名的”UDP打洞技术”.这里将考虑两种典型场景,来介绍连接的双方应用程序如何按照计划的进行通信的,第一种场景,我们假设两个客户端都处于不同的NAT之后;第二种场景,我们假设两个客户端处于同一个NAT之后,但是它们彼此都不知道(他们在同一个NAT中).

处于不同NAT之后的客户端通信

我们假设 Client A和Client B都拥有自己的私有IP地址,并且都处在不同的NAT之后,端对端的程序运行于 CLIENT A,CLIENT B,S之间,并且它们都开放了UDP端口1234. CLIENT A和CLIENT B首先分别与S建立通信会话,这时NAT A把它自己的UDP端口62000分配给CLIENT A与S的会话,NAT B也把自己的UDP端口31000分配给CLIENT B与S的会话.如下图所示:

123456789101112

假如这个时候 CLIENT A 想与 CLIENT B建立一条UDP通信直连,如果 CLIENT A只是简单的发送一个UDP信息到CLIENT B的公网地址 
138.76.29.7:31000的话,NAT B会不加考虑的将这个信息丢弃(除非NAT B是一个 full cone NAT),因为这个UDP信息中所包含的地址信息,与CLIENT B和服务器S建立连接时存储在NAT B中的服务器S的地址信息不符.同样的,CLIENT B如果做同样的事情,发送的UDP信息也会被NAT A丢弃.

假如 CLIENT A 开始发送一个UDP信息到CLIENT B的公网地址上,与此同时,他又通过S中转发送了一个邀请信息给CLIENT B,请求CLIENT B也给CLIENT A发送一个UDP信息到 CLIENT A的公网地址上.这时CLIENT A向CLIENT B的公网IP(138.76.29.7:31000)发送的信息导致 NAT A 打开一个处于CLIENT A的私有地址和CLIENT B的公网地址之间的新的通信会话,与此同时NAT B也打开了一个处于CLIENT B的私有地址和CLIENT A的公网地址(155.99.25.11:62000)之间的新的通信会话.一旦这个新的UDP会话各自向对方打开了,CLIENT A和CLIENT B之间就可以直接通信,而无需S来牵线搭桥了.这就是所谓的打洞技术. 
一旦这种处于NAT之后的端对端的直连建立之后,连接的双方可以轮流担任对方的”媒人”,把对方介绍给其他的客户端,这样就极大的降低了服务器S的工作量.

处于相同NAT之后的客户端通信

我们假设 Client A和Client B都拥有自己的私有IP地址,并且都处在相同的NAT之后,端对端的程序运行于 CLIENT A,CLIENT B,S之间, 
CLIENT A和CLIENT B分别与S建立通信会话,经过NAT转换后,A的公网端口被映射为62000,B的公网端口映射为62001.如下图所示:

123456789101112

根据前面介绍的”打洞”技术,CLIENT A将发送一个UDP信息到CLIENT B的公网地址上,数据包源端为(10.0.0.1:124),目的端为(155.99.25.11:62001).该数据包能否被B收到,取决于当前的NAT是否支持”发夹”转换(hairpin转换,也就是同一台设备不同端口之间的UDP数据包能否到达). 
首先,支持”发夹”转换的NAT设备还远没有支持”打洞”技术的NAT设备多,其次,即使NAT设备支持”发夹”转换,在这种情况下也应该通过网内端到端实现,而不是将数据包无谓 地经过NAT设备,这是一种对资源的浪费.

一般”打洞”过程

综合上面介绍的客户端处于不同NAT之后和处于同一NAT之后,我们说下一般的”打洞”过程.

  1. 打洞技术假定客户端A和B可以与公网内的已知的集中服务器建立UDP连接(可以互发UDP数据包).当一个客户端在S上登陆的时候,服务器记录下该客户端的两个endpoints(IP地址,UDP端口),一个是该客户端确信自己是通过该ip和端口与服务器S进行通信的,另一个是服务器S记录下的由服务器”观察”到的该客户端实际与自己通信所使用的ip和端口.我们可以把前一个endpoint看作是客户端的内网ip和端口,把后一个endpoint看作是客户端的内网ip和端口经过NAT转换后的公网ip和端口.服务器可以从客户端的登陆消息的消息体中得到该客户端的内网endpoint相关信息,可以通过对登陆消息的IP或UDP头得到该客户端的公网endpoint.

  2. 假设Client A想向B发起连接,于是A向服务器S发送消息,请求S帮助建立与B的UDP连接.这时,S将B的公网和内网的endpoint发给A.可知,A与B通过与S的一次通信就可以知道对方的公网和内网的endpoint. 

  3. Client A通过B的内网endpoint发送UDP数据包.针对5.3.2节问题的解决方案.如果B和A在同一NAT后,则很快收到响应.如果B和A不在同一NAT后,则超时.

  4. Client A通过B的外网endpoint发送UDP数据包. 
    回到5.3.1节介绍的具体方法.CLIENT A发出UDP包(10.0.0.1:1234,138.76.29.7:31000),经NAT A转换为(155.99.25.11:62000,138.76.29.7:31000),经NAT B转换为(155.99.25.11:62000,10.1.1.3:1234).如果在此数据包到达NAT B前,B发送过UDP包到A的公网endpoint,则NAT B允许此包到达B机.在5.3.2节下,A发出UDP包(10.0.0.1:1234,155.99.25.11:62001),NAT 先转换为(155.99.25.11:62000,155.99.25.11:62001),再转换为(155.99.25.11:62000,10.1.1.3:1234).

  5. 步骤3,4发送的数据包是为了”打洞”,打洞成功后,就进入真正的P2P传输了. 
    还有一种情况,B和A不在同一NAT后,C和A在同一NAT后,且B和C的内网endpoint一致,这个时候A从S拿到的目的端应该有2个.所以针对3,4步骤取先有回应的目的端不可取,应该先做步骤3,有回应直接到步骤5,没有回应到步骤4.


本文链接:https://www.it72.com/12524.htm

推荐阅读
最新回复 (0)
返回