P2P穿透理论:ICE STUN TURN

本文的主要工作是介绍ICE、STUN、TURN这几种协议。文章的目标并不是将这三个协议的内容翻译成中文,只是根据作者的理解,以及在Libjingle当中可能需要的重要部分而进行有选择性的分析。当然,如果有时间更加推荐去看原本的RFC文档,这一章的目标是分析,希望能够让对这些协议不了解的读者能够有一个基础的知识,能够为后面的Libjingle深入分析打好一个基础。本章分为四部分,第一部分介绍STUN协议,第二部分介绍TURN协议,第三部分介绍ICE协议,第四部分综合Libjingle和协议的内容进行一个简单的总结。每一部分都会有相应的实验,都会提取Libjingle中的相关代码来进行深入的分析。希望我的工作能够给你带来帮助和进步。

Libjingle到底是什么呢?在最开始的项目当中,Libjingle是用于支持XMPP协议及其相关扩展的一个Google Talk当中的程序。后面Libjingle初移植到了WebRTC当中,成为了WebRTC的网络核心部分。事实上,在Google Talk当中,它是Google Talk的网络核心部分,在WebRTC当中也是一样的。那么WebRTC的网络核心是什么,是线程、套节字、消息、还有非常重要的P2P连接。

而P2P连接主要实现的就是ICE(RFC 5245)协议,ICE协议是一个综合的P2P连接解决方案,它包含了专门用于打洞的STUN(RFC5389)协议和当打洞不成功时使用的TRUN(RFC5766)转发协议。除了这两种方案之后,还定义了一系列的规则来保证P2P的连接,这就是ICE。而Libjingle当中的P2P就是主要实现了ICE协议的内容,更广泛的说,Libjingle的主要核心内容就是实现ICE。Libjingle在Google上没有太多的原理性描述细节,实际上ICE就是Libjingle的最好的文档。

##STUN 协议 RFC5389

STUN协议有两个版本一个是2003年3月出版的RFC3489(STUN - Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs),一个是在2008年10月出版的RFC5389(Session Traversal Utilities for NAT (STUN))。而Libjingle支持的协议的RFC5389。在第一版的RFC当中,STUN被定义为一个使用UDP简单穿越NAT的解决方案,是一个完成的解决方案,而在新的RFC5389中STUN被定义为作为其它需要穿越NAT的协议的一个工具,比如ICE协议。

STUN协议的主要功能是用来打洞的,所谓打洞就是当两台计算分别处于不同的内网当中,他们之间想要直接连接,但是只知道自己在局域网内的IP地址,并不知道自己的外网IP地址,这样就根本不能够进行直接连接如图下图所示,所以这个时候就需要通过一定的方法来得到自己的外网IP地址,得到之后再通过一定的方法将两台计算机连接起来,这个过程就叫打洞,建立两台计算机之间的直接连接。

generator

在这里,知道对方的外网IP和端口之后,通过一定的方法将两台计算机连接并没有我们相像中的那么简单。由于各种各样的原因,现在的NAT从打洞上面,可以分为四类NAT,而可能穿越的NAT只有其中三类。有一些NAT很容易打洞,而有一些NAT却很难打洞成功,具体的在下面的章节当中我们会详细讨论。STUN协议主要有两种功能:

  1. 让一台计算机知道自己当前的数据包在外网(NAT之外)的IP地址和端口信息。
  2. 当两台计算机打洞成功之后,可以用来检查和保持端口之间的连接状态。

UDP的NAT穿越

对于UDP穿越NAT,现目前的应该当中有比较规范的穿越技术。这些穿越技术主要使用的是”反向连接技术”和 ”STUN”技术@NAT_TRAVERSAL_1。这两种技术综合起来,一般情况下可以穿越互联网上面的大多数的NAT设备,取得良好的效果差不多能够达到92%的效果(来自Google的数据)。但是这两种方法也不是万能的,总有一些NAT设备它不能够被这样简单的穿越,在文章的后面会详细讨论这个问题。

TCP的NAT穿越

对于TCP穿越NAT,在技术上面来说,这个问题非常的麻烦,由于TCP的连接特性,一般情况下是非常难以用TCP穿越NAT的。在现目前人们所做的研究当中,使用TCP穿越NAT的技术基本上分为两类。 第一类是NAT的规则非常的简单的情况进行穿越的算法。通过详细的会话测试集得到关于所属NAT设备的映射特性、过滤特性来判断这台计算要的端口是不是可以预测的。比如使用STUNT协议时它要求NAT映射的端口是连续的,或者同一端口发往同一IP地址的数据包被映射到相同的商品,只有在这些情况下才有可能被穿越@NAT_TRAVERSAL_2。否则就没有办法,在实际过程当中,这种NAT设备比较少。

第二类主是使用复杂的概率和综合各种情况来进行端口猜测,实现复杂,失败率非常高,很不实用。

所以,综合来说,使用TCP穿越NAT的技术到现在并没有一个比较好的解决方案。

客户端连接方法分析

在P2P建立过程当中,可能有时候有一些客户端和主机之间有时候隔着几层NAT,有时候隔着一层NAT,也有的时候它们之间在一个网络当中。还有的情况是一台客户端在NAT后面,一台客户端在公网上面。这些情况都需要具体考虑。在我们项目当中,一般情况下,两台连接的主机一台是显示客户端,一台是视频采集终端。

table_nat

如上表所示,不同情况下的P2P连接情况,我们重点讨论的是两台计算机都在NAT之后的连接方案。

##基于RFC4787的NAT分类

RFC4787按照NAT把内部IP地址和端口映射的行为,将NAT分为三类。按照NAT过虑外部网络的数据包行为也将NAT分为三类。

按端口映射行为分类

按过滤行为分类

##基于STUN的NAT功能分类

NAT 主要分为两类一种是基本的NAT,另一种是NAPT (Network Address/Port Translator)。第一种NAT就是在地址转换过程当中只转换IP地址,而不会改变端口,而第二种会同时改变端口,在现目前的应用情况下,NAPT的设备最为常见。为了与其它资料兼容,在这篇文章当中,所有的NAT基本上代表的是NAPT。

STUN执行过程当中,按NAT对端口的映射方式将其分为四种类型。

Full-cone NAT

这种NAT同时也称为one-to-one NAT。这种NAT的特点是一个内网的IP地址和端口被映射成一个外网的IP地址和端口(eAddr:ePort)。从内网中的iAddr:IPort端口所发送的任何数据都是都是通过这个外网固定eAddre:ePort发送出去的。同时任何外网的不同主机发送给这个NAT设备的eAddr:EPort的信息都将会转发到内网中iAddr:iPort当中去,如下图所示。

full-cone

(Address)-Restricted-cone NAT

和Full-cone NAT一样,一个内网的IP地址和端口被映射成一个外网的IP地址和端口(eAddr:ePort)。从内网中的iAddr:IPort端口所发送的任何数据都是都是通过这个外网固定eAddre:ePort发送出去的。但是对于外网的主机,只有内网发送的目标主机发送的数据才能通过NAT的这个端口。这个目标主机的任意端口都可以通过这个端口,如下图所示。

Restricted-cone

Port-Restricted Cone NAT

和上面的两类非常相同,同样是端口一一映射。但是外网的主机只允许目标主机的目标端口的数据才能通过NAT到达内网的主机,如下图所示。

port_nat

Symmetric NAT

这种NAT与前面三种有非常大的不同,内网中的主机所发送的数据只要是不同的外网主机NAT都为它分配一个不同的端口,而内网的主机即使使用的同一个端口,只要发送的目标是不同的主机。那么NAT都会为之重要分配一个端口。而对于外网的主机,NAT只接受固定的外网主机的固定端口访问,如下图所示。

symmetric

这一种类型的NAT在穿越的时候实际上几乎不可能的,不过幸好,由于这种NAT的实现比较复杂,所以在现实的应用当中比较少。

##STUN协议的工作原理

在网上的STUN协议都基本上出自2003年出版的RFC3489,全称为Simple Traversal of User Datagram Protocol(UDP) Through Network Address Translators(NATs)[4] 。但是在2008年RFC5389对STUN协议进行了一些改动,这个时候的STUN的英文全称是Session Traversal Utilities for NAT。原本RFC3489声称STUN是一个完全的穿越NAT的解决方案,而在新的RFC5389中,称原本的RFC3489只是穿越NAT的其中一种工具。新的STUN最大的改变就是增加了对TCP穿越的支持。

对于STUN的TCP穿越,现在还没有具体研究,但是基于先前的分析,可预测其结果也应该不会有太大的改变。

STUN的主要工作原理就是利用外网的计算机来辅助本地的计算机穿越NAT,得到本地计算机的外网IP地址和端口。STUN在工作过程当中需要服务器有两个公网的IP地址,或者两台公网上面的服务器。其实经过对NAT的分类,我们就已经发现了,只有前面三种NAT才有可能穿越。Symmetric NAT不能够穿越。

为了更了的分析STUN的运行原理,图[STUN~T~HEROM]是一个STUN的解析图,在这个图当中,有两台客户计算机分别在NAT后面,在公网上面还有一个SERVER,它有两个IP地址。现在我们模拟STUN协议的运行过程。

all_frame_two