WebRTC学习(二):WebRTC 传输协议

我们知道WebRTC要解决的是两个浏览器之间如何进行实时音视频互动的问题。从底层来看,就是要解决两个点之间如何进行高效的网络传输。这就涉及要很多重要的传输协议,下面我们针对涉及到的协议进行梳理和说明。

一、NAT(Network Address Translator)

NAT主要做的事情就是地址映射,其作用就是将内网的主机经过NAT的映射生成外网的ip地址和端口,如下图所示:

NAT产生的原因如下:

  • IPV4的地址不够。
  • 处于安全考虑,保证某局域网下的设备的安全。

NAT的种类有以下几种:

  • 完全锥型NAT:所有从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号,并且任何一个外网主机都可以通过这个映射的外网IP和端口号向这台内网主机发送包。
  • 地址限制锥型NAT:它也是所有从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号。与完全锥形不同的是,外网主机只能够向先前已经向它发送过数据包的内网主机发送包。
  • 端口限制锥型NAT:端口限制锥形NAT与限制锥形NAT很相似,只不过它包括端口号。也就是说,一台IP地址X和端口P的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个IP地址X和端口P发送过数据包。
  • 对称型NAT:所有从同一个内网IP和端口号发送到一个特定的目的IP和端口号的请求,都会被映射到同一个IP和端口号。如果同一台主机使用相同的源地址和端口号发送包,但是发往不同的目的地,NAT将会使用不同的映射。此外,只有收到数据的外网主机才可以反过来向内网主机发送包。

二、STUN(Session Traversal Utilities for NAT)

STUN即NAT会话穿透实用工具[RFC5389],用于进行UAT穿透,采用的是典型的客户端/服务端模式。客户端发送请求,服务端进行响应。

STUN是一个C/S架构的协议,支持两种传输类型。一种是请求/响应类型,由客户端给服务端发送请求并等待服务端响应;另一种是指示类型,由服务器或者客户端发送指示,另一方不产生响应。两种类型的传输都包含一个96位的随机数作为事务ID(transaction ID),对于请求/响应类型,事务ID允许客户端将响应和产生响应的请求连接起来;对于指示类型,事务ID通常作为debugging aid使用。

STUN报文和大多数网络类型的格式一样,是以大端编码(big-endian)的,即最高有效位在左边。所有的STUN报文都以20字节(160位)的头部开始,后面跟着若干个属性。

2.1 STUN报文头部

STUN头部包含了STUN消息类型,magic cookie,事务ID和消息长度,如下:

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |0 0|     STUN Message Type     |         Message Length        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                         Magic Cookie                          |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                                                               |
  |                     Transaction ID (96 bits)                  |
  |                                                               |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

下面来说明一下报文头部的各个数据的意义:

  • 前两位必须设置为00,这样可以在当STUN和其他协议复用的时候,用来区分STUN包和其他数据包,如RTP数据的报头前两位为01。
  • Message Length 字段存储了信息的长度,以字节为单位,不包括20字节的STUN头部。由于所有的STUN属性都是都是4字节对齐(填充)的,因此这个字段最后两位应该恒等于零,这也是辨别STUN包的一个方法之一。
  • STUN Message Type 是14位是消息类型,其中包括消息类型和消息主方法。
  • Magic Cookie 字段包含固定值0x2112A442,这是为了前向兼容RFC3489,因为在classic STUN中,这一区域是事务ID的一部分。另外选择固定数值也是为了服务器判断客户端是否能识别特定的属性。还有一个作用就是在协议多路复用时候也可以将其作为判断标志之一。
  • Transaction ID 字段是个96位的标识符,用来区分不同的STUN传输事务。对于request/response传输,事务ID由客户端选择, 服务器收到后以同样的事务ID返回response;对于indication则由发送方自行选择。事务ID的主要功能是把request和response联系起来,同时也在防止攻击方面有一定作用。服务端也把事务ID当作一个Key来识别不同的STUN客户端,因此必须格式化且随机在0~2^(96-1)之间。重发同样的request请求时可以重用相同的事务ID,但是客户端进行新的传输时,必须选择一个新的事务ID。

2.2 STUN 属性

在STUN报文头部之后,通常跟着0个或者多个属性,每个属性必须是TLV编码的(Type-Length-Value)。其中Type字段和Length字段都是16位,如下:

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |         Type                  |            Length             |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                         Value (variable)                ....
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.3 STUN 通信过程

1. 产生一个Request或Indication

当产生一个Request或者Indication报文时,终端必须根据上文提到的规则来生成头部,class字段必须是Request或者Indication,而method字段为Binding或者其他用户拓展的方法。属性部分选择该方法所需要的对应属性。

2. 发送Requst或Indication

目前,STUN报文可以通过UDP,TCP以及TLS-over-TCP的方法发送,其他方法在以后也会添加进来。STUN的使用者必须指定其使用的传输协议,以及终端确定接收端IP地址和端口的方式。

下面说明一下使用不同方式发送报文的通信机制:

  • 通过UDP发送:当使用UDP协议运行STUN时,STUN的报文可能会由于网络问题而丢失。可靠的STUN请求/响应传输是通过客户端重发request请求来实现的,因此,在UDP运行时,Indication报文是不可靠的。STUN客户端通过RTO(Retransmission TimeOut)来决定是否重传Requst,并且在每次重传后将RTO翻倍。具体重传时间的选取可以参考相关文章,如RFC2988。重传直到接收到Response才停止,或者重传次数到达指定次数Rc,Rc应该是可配置的,且默认值为7。
  • 通过TCP或者TCP-over-TLS发送:对于这种情景,客户端打开对服务器的连接。在某些情况下,此TCP链接只传输STUN报文,而在其他拓展中,在一个TCP链接里可能STUN报文和其他协议的报文会进行多路复用(Multiplexed)。数据传输的可靠性由TCP协议本身来保证。值得一提的是,在一次TCP连接中,STUN客户端可能发起多个传输,有可能在前一个Request的Response还没收到时就再次发送了一个新的Request,因此客户端应该在确认所有STUN事务都已完成之前保持TCP链接打开。

3. 接受STUN消息

当STUN终端接收到一个STUN报文时,首先检查报文的规则是否合法,即前两位是否为0,magic cookie是否为0x2112A442,报文长度是否正确以及对应的方法是否支持。
如果消息类别为Success/Error Response,终端会检测其事务ID是否与当前正在处理的事务ID相同。如果使用了FINGERPRINT拓展的话还会检查FINGERPRINT属性是否正确。
完成身份认证检查之后,STUN终端会接着检查其余未知属性。

3.1 处理Request

如果请求包含一个或者多个强制理解的未知属性,接收端会返回error response,错误代码420(ERROR-CODE属性),
而且包含一个UNKNOWN-ATTRIBUTES属性来告知发送方哪些强制理解的属性是未知的。服务端接着检查方法和其他指定要求,如果所有检查都成功,
则会产生一个Success Response给客户端。

  • 3.1.1 生成Success Response或Error Response

    • 如果服务器通过某种验证方法(authentication mechanism)通过了请求方的验证,那么在响应报文里最好也加上对应的验证属性。
    • 服务器端也应该加上指定方法所需要的属性信息,另外协议建议服务器返回时也加上SOFTWARE属性。
    • 对于Binding方法,除非特别指明,一般不要求进行额外的检查。当生成Success Response时,服务器在响应里加上XOR-MAPPED-ADDRESS属性。
      对于UDP,这是其源IP和端口信息,对于TCP或TLS-over-TCP,这就是服务器端所看见的此次TCP连接的源IP和端口。
  • 3.1.2 发送Success Response或Error Response

    • 发送响应时候如果是用UDP协议,则发往其源IP和端口,如果是TCP则直接用相同的TCP链接回发即可。

3.2 处理Indication

如果Indication报文包含未知的强制理解属性,则此报文会被接收端忽略并丢弃。如果对Indication报文的检查都没有错误,则服务端会进行相应的处理,
但是不会返回Response。对于Binding方法,一般不需要额外的检查或处理。收到信息的服务端仅需要刷新对应NAT的端口绑定。

由于Indication报文在用UDP协议传输时不会进行重传,因此发送方也不需要处理重传的情况。

3.3 处理Success Response

如果Success Response包含了未知的强制理解属性,则响应会被忽略并且认为此次传输失败。客户端对报文进行检查通过之后,就可以开始处理此次报文。

以Binding方法为例,客户端会检查报文中是否包含XOR-MAPPED-ADDRESS属性,然后是地址类型,如果是不支持的地址类型,则这个属性会被忽略掉。

3.4 处理Error Response

如果Error Response包含了未知的强制理解属性,或者没有包含ERROR-CODE属性,则响应会被忽略并且认为此次传输失败。
随后客户端会对验证方法进行处理,这有可能会产生新的传输。

  • 到目前为止,对错误响应的处理主要基于ERROR-CODE属性的值,并遵循如下规则:

    • 如果error code在300到399之间,客户端被建议认为此次传输失败,除非用了ALTERNATE-SERVER拓展;
    • 如果error code在400到499之间,客户端认为此次传输失败;
    • 如果error code在500到599之间,客户端可能会需要重传请求,并且必须限制重传的次数。

任何其他的error code值都会导致客户端认为此次传输失败。

三、TURN(Traversal Using Replays around NAT) 

TURN的全称为Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,主要添加了Relay功能。如果终端在NAT之后,那么在特定的情景下,有可能使得终端无法和其对等端(peer)进行直接的通信,这时就需要公网的服务器作为一个中继,对来往的数据进行转发。这个转发的协议就被定义为TURN。TURN和其他中继协议的不同之处在于,它允许客户端使用同一个中继地址(relay address)与多个不同的peer进行通信。

如果TURN使用于ICE协议中,relay地址会作为一个候选,由ICE在多个候选中进行评估,选取最合适的通讯地址。一般来说中继的优先级都是最低的。TURN协议被设计为ICE协议(Interactive Connectivity Establishment)的一部分,而且也强烈建议用户在他们的程序里使用ICE,但是也可以独立于ICE的运行。值得一提的是,TURN协议本身是STUN的一个拓展,因此绝大部分TURN报文都是STUN类型的,作为STUN的一个拓展,TURN增加了新的方法(method)和属性(attribute)。

操作概述

在典型的情况下,TURN客户端连接到内网中,并且通过一个或者多个NAT到达公网,TURN服务器架设在公网中,不同的客户端以TURN服务器为中继和其他peer进行通信,如下图所示:

                                        Peer A
                                        Server-Reflexive    +---------+
                                        Transport Address   |         |
                                        192.0.2.150:32102   |         |
                                            |              /|         |
                          TURN              |            / ^|  Peer A |
    Client’s              Server            |           /  ||         |
    Host Transport        Transport         |         //   ||         |
    Address               Address           |       //     |+---------+
   10.1.1.2:49721       192.0.2.15:3478     |+-+  //     Peer A
            |               |               ||N| /       Host Transport
            |   +-+         |               ||A|/        Address
            |   | |         |               v|T|     192.168.100.2:49582
            |   | |         |               /+-+
 +---------+|   | |         |+---------+   /              +---------+
 |         ||   |N|         ||         | //               |         |
 | TURN    |v   | |         v| TURN    |/                 |         |
 | Client  |----|A|----------| Server  |------------------|  Peer B |
 |         |    | |^         |         |^                ^|         |
 |         |    |T||         |         ||                ||         |
 +---------+    | ||         +---------+|                |+---------+
                | ||                    |                |
                | ||                    |                |
                +-+|                    |                |
                   |                    |                |
                   |                    |                |
             Client’s                   |            Peer B
             Server-Reflexive    Relayed             Transport
             Transport Address   Transport Address   Address
             192.0.2.1:7000      192.0.2.15:50000     192.0.2.210:49191

在上图中,左边的TURN Client是位于NAT后面的一个客户端(内网地址是10.1.1.2:49721),连接公网的TURN服务器(默认端口3478)后,服务器会得到一个Client的反射地址(Reflexive Transport Address, 即NAT分配的公网IP和端口)192.0.2.1:7000,此时Client会通过TURN命令创建或管理ALLOCATION,allocation是服务器上的一个数据结构,包含了中继地址的信息。服务器随后会给Client分配一个中继地址,即图中的192.0.2.15:50000,另外两个对等端若要通过TURN协议和Client进行通信,可以直接往中继地址收发数据即可,TURN服务器会把发往指定中继地址的数据转发到对应的Client,这里是其反射地址。

Server上的每一个allocation都唯一对应一个client,并且只有一个中继地址,因此当数据包到达某个中继地址时,服务器总是知道应该将其转发到什么地方。但值得一提的是,一个Client可能在同一时间在一个Server上会有多个allocation,这和上述规则是并不矛盾的。

传输

在协议中,TURN服务器与peer之间的连接都是基于UDP的,但是服务器和客户端之间可以通过其他各种连接来传输STUN报文,比如TCP/UDP/TLS-over-TCP. 客户端之间通过中继传输数据时候,如果用了TCP,也会在服务端转换为UDP,因此建议客户端使用UDP来进行传输. 至于为什么要支持TCP,那是因为一部分防火墙会完全阻挡UDP数据,而对于三次握手的TCP数据则不做隔离.

分配(Allocations)

要在服务器端获得一个中继分配,客户端须使用分配事务. 客户端发送分配请求(Allocate request)到服务器,然后服务器返回分配成功响应,并包含了分配的地址.客户端可以在属性字段描述其想要的分配类型(比如生命周期).由于中继数据实现了安全传输,服务器会要求对客户端进行验证,主要使用STUN的 long-term credentail mechanism.

发送机制(Send Mechanism)

client和peer之间有两种方法通过TURN server交换应用信息,第一种是使用SendData方法(method),第二种是使用通道(channels),两种方法都通过某种方式告知服务器哪个peer应该接收数据,以及服务器告知client数据来自哪个peer.

Send Mechanism使用了Send和Data指令(Indication).其中Send指令用来把数据从client发送到server,而Data指令用来把数据从server发送到client.

四、ICE(Interactive Connectivity Establishment)

ICE跟STUN和TURN不一样,ICE不是一种协议,而是一个框架(Framework),它整合了STUN和TURN。

其模型如下:

如上图所示,如果A想与B通信,那么其过程如下:

1). A收集所有的IP地址,并找出其中可以从STUN服务器和TURN服务器收到流量的地址;

2). A向STUN服务器发送一份地址列表,然后按照排序的地址列表向B发送启动信息,目的是实现节点间的通信;

3). B向启动信息中的每一个地址发送一条STUN请求;

4). A将第一条接收到的STUN请求的回复信息发送给B;

5). B接到STUN回复后,从中找出那些可在A和B之间实现通信的地址;

6). 利用列表中的排序列最高的地址进一步的设备间通信。

由于该技术是建立在多种NAT穿透协议的基础之上,并且提供了一个统一的框架,所以ICE具备了所有这些技术的优点,同时还避免了任何单个协议可能存在的缺陷。因此,ICE可以实现在未知网络拓扑结构中实现的设备互连,而且不需要进行对手配置。另外,由于该技术不需要为VoIP流量手动打开防火墙,所以也不会产生潜在的安全隐患。

五、参考文章:

1). P2P通信标准协议(一)之STUN:https://www.cnblogs.com/pannengzhi/p/5041546.html

2). STUN和TURN技术浅析:https://blog.csdn.net/dxpqxb/article/details/75003701

3). P2P技术详解(四):P2P技术之STUN、TURN、ICE详解:http://www.52im.net/forum.php?mod=viewthread&tid=557&highlight=ICE

posted @ 2017-02-10 19:05  灰色飘零  阅读(8641)  评论(0编辑  收藏  举报