p2p 技术

P2P

blob.png

P2P技术是实现两个主机间的直接通信,当两个主机都拥有公网IP时,两者建立通信链路很简单,当其中一个主机处在一个局域网内,拥有一个私网IP时,我们可以通过NAT技术建立实现两个主机之间通信的链路;当两个主机分别都处在两个不同局域网内,拥有各自的私网IP,它们之间该如何之间通信呢?我们所熟知的聊天工具如QQSkype的文件传输和一些下载工具Bittorent等都会碰到此问题。P2P技术是在NAT(Network Address Translation,网络地址转换)穿越(打洞)基础上实现的。

 

关于NATNAT穿越

NAT基本分类:

Ø  基本的NAT

下图描述了基本的NAT操作流程

blob.png

注意:基本的NAT会改变IP包中的原IP地址,但是不会改变IP包中的端口。现在我们使用的NAT都是NAPTNAT已被淘汰。

Ø  NAPT

下图描述NAPT的操作流程

blob.png

注:上图中的20.1.1.1改为10.1.1.1

packet1packet2显示的是同一主机的相同IP(同一网卡)的不同端口的地址转换情形;packet3packet4显示的是同一主机不同IP(不同网卡)的相同端口的地址转换情形。

例如:packet1的目的地址是10.1.1.2:80,其地址转换如下:

blob.png

由上图可知当外网10.1.1.2:80访问10.1.1.12001号端口时,NAT会将该数据包转发给192.168.1.3:1537,也就是说NAT2001端口对应着192.168.1.3:1537。(注意:对于其他的IP即除了10.1.1.2发送到该2001端口的数据包会被NAT抛弃

NAPT又可以分为:

*  Symmetric NAT

*  Cone NAT

packet1会话已将IP 192.168.1.3绑定了1537端口并与外网地址10.1.1.1:80建立了链路,如果此时该会话向另一主机10.1.1.3:2222,那么此时该数据包通过NAT地址会进行怎样转换呢?

这种情况下NAT会有两种处理方法。一种是NAT再次创建一个session,并将此session分配一个端口号(如2002);另一种是NAT再次创建一个session但不会分配新的端口号而是仍然使用原来分配的端口号2001。第一种情况就是symmetric NAT,第二种情况就是cone NAT

对于实现P2P大部分都是使用cone NATsymmetric NAT也可实现但是相对复杂。

Cone NAT类型

²  Full Cone

IP、端口都不受限。只要客户端由内到外打通一个洞之后(NatIP:NatPort>A:P1),其他IP的主机(B)或端口(A:P2)都可以使用这个洞发送数据到客户端。

blob.png

²  Restricted Cone

IP受限,端口不受限。当客户端由内到外打通一个洞之后(NatIP:NatPort>A:P1)A机器可以使用他的其他端口(P2)主动连接客户端,但B机器则不被允许。

blob.png

²  Port Restricted Cone

IP、端口都受限。返回的数据只接受曾经打洞成功的对象(A:P1),由A:P2B:P1发起的数据将不被NatIP:NatPort接收。

blob.png

Symmetric NAT—对称型NAT

对称型NAT具有端口受限锥型的受限特性。但更重要的是,他对每个外部主机或端口的会话都会映射为不同的端口(洞)。只有来自相同的内部地址(IP:PORT)并且发送到相同外部地址(X:x)的请求,在NAT上才映射为相同的外网端口,即相同的映射。

对于cone NAT型,同一client打的洞都相同,但symmetric NAT会变。

NAT分类总结:

blob.png

P2P的实现

Ø  普通直连式P2P实现

blob.png

这里client Aclient B实现P2P直接通信前client需要登陆server,然后server会知道与各个client通信地址,接下来sever会想一个client A发送打洞命令(当然洞的方向是指向另一个client B),这样client Bserver获得client A的地址就可以直接与client A通信了。

Ø  STUN方式实现

STUN(Session Traversal Utilities for NAT)RFC3489规定的一种NAT穿透方式,它采用辅助的方法探测NATIP和端口。毫无疑问的,它对穿越早期的NAT起了巨大的作用,并且还将继续在NAT穿透中占有一席之地。

blob.png

STUN的探测过程需要有一个公网IPSTUN server,在NAT后面的UAC必须和此server配合,互相之间发送若干个UDP数据包。UDP包中包含有UAC需要了解的信息,比如NAT外网IPPORT等等。UAC通过是否得到这个UDP包和包中的数据判断自己的NAT类型。

假设有如下UACB),NATA),SERVERC),UACIPIPBNATIP IPA SERVER IPIPC1 IPC2。请注意,服务器C有两个IP,后面你会理解为什么需要两个IP

NAT的探测过程:

STEP1BCIPC1port1端口发送一个UDP包。C收到这个包后,会把它收到包的源IPport写到UDP包中,然后把此包通过IP1Cport1发还给B。这个IPport也就是NAT的外网IPport,也就是说你在STEP1中就得到了NAT的外网IP

熟悉NAT工作原理的应该都知道,C返回给B的这个UDPB一定收到。如果在你的应用中,向一个STUN服务器发送数据包后,你没有收到STUN的任何回应包,那只有两种可能:1STUN服务器不存在,或者你弄错了port2、你的NAT设备拒绝一切UDP包从外部向内部通过,如果排除防火墙限制规则,那么这样的NAT设备如果存在,那肯定是坏了。

B收到此UDP后,把此UDP中的IP和自己的IP做比较,如果是一样的,就说明自己是在公网,下步NAT将去探测防火墙类型,就不多说了(下面有图)。如果不一样,说明有NAT的存在,系统进行STEP2的操作。

STEP2BCIPC1发送一个UDP包,请求C通过另外一个IPC2PORT(不同与SETP1IP1)向B返回一个UDP数据包(现在知道为什么C要有两个IP了吧,为了检测cone NAT的类型)。

我们来分析一下,如果B收到了这个数据包,那说明什么?说明NAT来着不拒,不对数据包进行任何过滤,这也就是STUN标准中的full cone NAT。遗憾的是,full cone nat太少了,这也意味着你能收到这个数据包的可能性不大。如果没收到,那么系统进行STEP3的操作。

STEP3BCIPC2port2发送一个数据包,C收到数据包后,把它收到包的源IPport写到UDP包中,然后通过自己的IPC2port2把此包发还给B

step1一样,B肯定能收到这个回应UDP包。此包中的port是我们最关心的数据,下面我们来分析:

如果这个portstep1中的port一样,那么可以肯定这个NAT是个CONE NAT,否则是对称NAT。道理很简单:根据对称NAT的规则,当目的地址的IPport有任何一个改变,那么NAT都会重新分配一个port使用,而在step3中,和step1对应,我们改变了IPport。因此,如果是对称NAT,那这两个port肯定是不同的。

如果在你的应用中,到此步的时候PORT是不同的,那就只能放弃P2P了,原因同上面实现中的一样。如果不同,那么只剩下了restrict cone port restrict cone。系统用step4探测是是那一种。

STEP4BCIP2的一个端口PD发送一个数据请求包,要求CIP2和不同于PDport返回一个数据包给B

我们来分析结果:如果B收到了,那也就意味着只要IP相同,即使port不同,NAT也允许UDP包通过。显然这是restrict cone NAT。如果没收到,没别的好说,port restrict NAT.

Stun算法流程图如下:

blob.png

Libjingle

Libjingle是一个方便实现P2P传输的开源库,由google公司开发,并于20051215日发布第一个版本。

 

参考

http://www.h3c.com/portal/Products___Technology/Technology/Security_and_VPN/Technology_Introduction/200701/195612_57_0.htm

http://www.cppblog.com/peakflys/archive/2013/01/25/197562.html

http://lifeofzjs.com/blog/2014/07/19/how-p2p-in-symmetric-nat/

A Python STUN client for getting NAT type and external IPhttps://github.com/jtriley/pystun

p2p原理和常见的实现方式(libjingle

Python实现STUN+TURN+P2P聊天

Python P2P chat

Welcome to the stunserver wiki!

https://github.com/jselbie/stunserver/wiki

python socket udp编程

https://hacks.mozilla.org/2013/07/webrtc-and-the-ocean-of-acronyms/

STUNTURN技术浅析

Libjingle source code