p2p打洞技术原理

什么是打洞,为何要打洞

因为Internet的快速发展 IPV4(网际协议版本4)地址不够用,不能每一个主机分到一个公网IP 因此使用NAT地址转换api

通常来讲都是由私网内主机主动发起链接,数据包通过NAT地址转换后送给公网上的服务器,链接创建之后可双向传送数据,NAT设备容许私网内主机主动向公网内主机发送数据,但却禁止反方向的主动传递,但在一些特殊的场合须要不一样私网内的主机进行互联(例如P2P软件、网络会议、视频传输等),TCP穿越NAT的问题必须解决。服务器

nat的几种类型

如今基本使用这种,又分为对称和锥型NAT。网络

锥型NAT,有彻底锥型、受限制锥型、端口受限制锥型三种:session

  • a)Full Cone NAT(彻底圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的全部请求都映射成同一个公网地址端口1.2.3.4:62000 ,192.168.0.8能够收到任意外部主机发到1.2.3.4:62000的数据报。
  • b)Address Restricted Cone NAT (地址限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的全部请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先给服务器C 6.7.8.9发送一个数据报后,192.168.0.8才能收到6.7.8.9发送到1.2.3.4:62000的数据报。
  • c)Port Restricted Cone NAT(端口限制圆锥型):从同一私网地址端口192.168.0.8:4000发至公网的全部请求都映射成同一个公网地址端口1.2.3.4:62000,只有当内部主机192.168.0.8先向外部主机地址端口6.7.8.9:8000发送一个数据报后,192.168.0.8才能收到6.7.8.9:8000发送到1.2.3.4:62000的数据报。

 对称NATsocket

  对于这种NAT。链接不一样的外部Server,NAT打开的端口会变化。也就是内部机器A链接外网机器B时,NAT会打开一个端口,链接外网机器C时又会打开另一个端口。tcp

对于双方都是Port Restricted Cone NAT的时候,则须要利用UDP打洞原理进行“先打洞,而后才能直接通讯”。spa

NAT进行打洞的流程与原理

若是A和B想要进行UDP通讯,则必须穿透双方的NAT路由。假设为NAT-A和NAT-B。设计

    

    A发送数据包到公网S,B发送数据包到公网S,则S分别获得了A和B的公网IP,code

S也和A B 分别创建了会话,由S发到NAT-A的数据包会被NAT-A直接转发给A,视频

由S发到NAT-B的数据包会被NAT-B直接转发给B,除了S发出的数据包以外的则会被丢弃。

因此:如今A B 都能分别和S进行全双工通信了,可是A B之间还不能直接通信。

 

    解决办法是:A向B的公网IP发送一个数据包,则NAT-A能接收来自NAT-B的数据包

并转发给A了(即B如今能访问A了);再由S命令B向A的公网IP发送一个数据包,则

NAT-B能接收来自NAT-A的数据包并转发给B了(即A如今能访问B了)。

以上就是“打洞”的原理。

 

UDP打洞的过程

一、双方都经过UDP与服务器通信后,网关默认就是作了一个外网IP和端口号 与你内网IP与端口号的映射,这个无需设置的,服务器也不须要知道客户的真正内网IP 

二、用户A先经过服务器知道用户B的外网地址与端口  

三、用户A向用户B的外网地址与端口发送消息,  

四、在这一次发送中,用户B的网关会拒收这条消息,由于它的映射中并无这条规则。  

五、可是用户A的网关就会增长了一条容许规则,容许接收从B发送过来的消息  

六、服务器要求用户B发送一个消息到用户A的外网IP与端口号  

七、用户B发送一条消息,这时用户A就能够接收到B的消息,并且网关B也增长了容许规则  

八、以后,因为网关A与网关B都增长了容许规则,因此A与B均可以向对方的外网IP和端口号发送消息。

 

TCP打洞技术

tcp打洞也须要NAT设备支持才行。

tcp的打洞流程和udp的基本同样,但tcp的api决定了tcp打洞的实现过程和udp不同。

tcp按cs方式工做,一个端口只能用来connect或listen,因此须要使用端口重用,才能利用本地nat的端口映射关系。(设置SO_REUSEADDR,在支持SO_REUSEPORT的系统上,要设置这两个参数。)

 

链接过程:(以udp打洞的第2种状况为例(典型状况))

nat后的两个peer,A和B,A和B都bind本身listen的端口,向对方发起链接(connect),即便用相同的端口同时链接和等待链接。由于A和B发出链接的顺序有时间差,假设A的syn包到达B的nat时,B的syn包尚未发出,那么B的nat映射尚未创建,会致使A的链接请求失败(链接失败或没法链接,若是nat返回RST或者icmp差错,api上可能表现为被RST;有些nat不返回信息直接丢弃syn包(反而更好)),(应用程序发现失败时,不能关闭socket,closesocket()可能会致使NAT删除端口映射;隔一段时间(1-2s)后未链接还要继续尝试);但后发B的syn包在到达A的nat时,因为A的nat已经创建的映射关系,B的syn包会经过A的nat,被nat转给A的listen端口,从而进去三次握手,完成tcp链接。

 

从应用程序角度看,链接成功的过程可能有两种不一样表现:(以上述假设过程为例)

一、链接创建成功表现为A的connect返回成功。即A端以TCP的同时打开流程完成链接。

二、A端经过listen的端口完成和B的握手,而connect尝试持续失败,应用程序经过accept获取到链接,最终放弃connect(这时可closesocket(conn_fd))。

多数Linux和Windows的协议栈表现为第2种。

 

但有一个问题是,创建链接的client端,其connect绑定的端口号就是主机listen的端口号,或许这个peer后续还会有更多的这种socket。虽然理论上说,socket是一个五元组,端口号是一个逻辑数字,传输层可以由于五元组的不一样而区分开这些socket,可是是否存在实际上的异常,还有待更多观察。

锥形nat打洞

对于Cone NAT.要采用UDP打洞.须要一个公网机器server C来充当”介绍人”.处于NAT以后的内网的A,B先分别和C通讯,打开各自的NAT端口.C这个时候知道A,B的公网IP: Port. 如今A和B想直接链接.好比A给B直接发包,除非B是Full Cone,不然不能通讯.反之亦然.

为何啊?由于对于处于NAT以后的A,B。若是想A要与外界的D通讯,则首先必需要A发包到D,而后A通过NAT设备NA,NA把A的内网地址和端口转换为NA的外网地址和端口。和D通讯以后,D才能通过NA和A通讯。也就是说,只能A和外界主动通讯,外界不能主动和处于NA以后的A通讯。这种包会被NA直接丢弃的。这也就是上面所说的Port Restricted Cone 的情形啊! A(192.168.8.100:5000) -> NA(202.100.100.100:8000) -> D(292.88.88.88:2000)可是咱们能够这样.

A --- NA --- Server C --- NB --- B

  • A,B 为主机;
  • NA, NB 为NAT设备;
  • Server C为外网的机器;
  1. 若是A想与B通讯;
  2. A首先链接 C, C获得A的外网NA的地址和端口;
  3. B也要链接C,C获得B的外网NB的地址和端口;
  4. A告诉C说我要和B通信;
  5. C经过NB发信息给B,告诉B A的外网NA的地址和端口;
  6. B向NA发数据包(确定会被NA丢弃,由于NA上并无 A->NB 的合法session),可是NB上就创建了有B->NA的合法session了;
  7. B发数据包给C,让 C 通知 A,我已经把洞打好了;
  8. A接受到通知后向 B 的外网发NB数据包,这样就不会被丢弃掉了。由于对于NB来讲,它看到的是A的外网NA的地址,而经过第6步,B已经让NA成为NB的合法通讯对象了。因此当NA发数据包给NB时,NB就会接收并转发给B;

注意: 路由器和防火墙的UDP打洞的端口有个时间限制的,在必定时间内若是没有数据通信会自动关闭

STUN

对称型nat打洞

image.png

  1. 为何能够发送消息,但不过去呢?

 

IP协议中TTL

把ttl的值设置小一点,好比4,使其路由转发的时候减到0,而把数据包丢弃

 

在IPv4中, TTL是IP协议的一个8个二进制位的值【0-255】. 这个值能够被认为是数据包在internet系统中能够跳跃的次数上限. TTL是由数据包的发送者设置的, 在前往目的地的过程当中, 每通过一台主机或设备, 这个值就要减小一. 若是在数据包到达目的地前, TTL值被减到了0,那么这个包将做为一个ICMP错误的数据包被丢弃。 Linux默认64

 

不少时候,咱们但愿网络中的两台主机可以直接进行通讯,即所谓的P2P通讯,而不须要其余公共服务器的中转。因为主机可能位于防火墙或NAT以后,在进行P2P通讯以前,咱们须要进行检测以确认它们之间可否进行P2P通讯以及如何通讯。这种技术一般称为NAT穿透(NAT Traversal)。最多见的NAT穿透是基于UDP的技术,如RFC3489中定义的STUN协议。

STUN和TURN技术浅析

STUN

STUN(Simple Traversal of User Datagram Protocol Through Network Address Translators),即简单的用UDP穿透NAT,是个轻量级的协议,是基于UDP的完整的穿透NAT的解决方案。它容许应用程序发现它们与公共互联网之间存在的NAT和防火墙及其余类型。它也可让应用程序肯定NAT分配给它们的公网IP地址和端口号。STUN是一种Client/Server的协议,也是一种Request/Response的协议,默认端口号是3478。

 

流程

应用程序(即STUN CLIENT)向NAT外的STUN SERVER经过UDP发送请求STUN 消息询问自身的转换后地址,STUN SERVER收到请求消息,产生响应消息,响应消息中携带请求消息的源端口,即STUN CLIENT在NAT上对应的外部端口。而后响应消息经过NAT发送给STUN CLIENT,STUN CLIENT经过响应消息体中的内容得知其在NAT上对应的外部地址,而且将其填入之后呼叫协议的UDP负载中,告知对端,同时还能够在终端注册时直接注册这个转换后的公有IP地址,这样就解决了H.323/MGCP/SIP穿越NAT的通讯创建问题以及做为被叫时的问题。本端的接收地址和端口号为NAT外的地址和端口号。因为经过STUN协议已在NAT上预先创建媒体流的NAT映射表项,故媒体流可顺利穿越NAT。

 

另外STUN server并不是指一个专用的服务器,而是指一种功能、一个协议,咱们能够在softswitch或者任何一个须要此功能的服务器上内置此协议, 后面代码也包含一个简单的Server实现。

可是在NAT采用对称模式(symmetric NAT)工做时,STUN的方案就会出现问题。假如咱们在softswitch上提供STUN server功能,终端A经过STUN能够得到NAT为终端A与softswitch之间通讯分配的地址A',并将这个地址注册在softswitch上,当一个公网上的终端B呼叫终端A时,A'和B经过softswitch完成呼叫创建过程。当B试图向A'发送媒体流时,问题就出现了。由于对称NAT只容许从softswitch发送数据给地址A',从B发送的媒体流将被丢弃。因此STUN没法应用于工做在对称模式的NAT.

STUN协议最大的优势是无需现有NAT/FW设备作任何改动,同时STUN方式可在多个NAT串联的网络环境中使用. STUN的局限性在于STUN并不适合支持TCP链接的穿越,同时STUN方式不支持对对称NAT(Symmetric NAT).

TURN

在RFC5766中定义,英文全称Traversal Using Relays around NAT(TURN):Relay Extensions to Session Traversal Utilities for NAT(STUN),即便用中继穿透NAT:STUN的中继扩展。简单的说,TURN与STUN的共同点都是经过修改应用层中的私网地址达到NAT穿透的效果,异同点是TURN是经过两方通信的“中间人”方式实现穿透。

若是一个主机位于NAT的后面,在某些状况下它不可以与其余主机点对点直接链接。在这些状况下,它须要使用中间网点提供的中继链接服务。TURN协议就是用来容许主机控制中继的操做而且使用中继与对端交换数据。TURN与其余中继控制协议不一样的是它可以容许一个客户端使用一个中继地址与多个对端链接。

TURN协议被设计为ICE的一部分,用于NAT穿越,虽然如此,它也能够在没有ICE的地方单独使用。

相关文章
相关标签/搜索