ZYB ARTICLES REPOS

RFC5766(TURN)中文翻译文档

Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)

翻译

本文翻译的文档为: RFC5766

原文地址为: https://www.rfc-editor.org/rfc/rfc5766

本文尚未完全翻译,同时也有一些翻译错误和不完美的地方,欢迎在 https://github.com/acevest/rfc_zh_CN 处提交RP。

点此查看中文文档

引用请注明出处: https://zhaoyanbai.com/articles/RFC5766_TURN_zh_CN

概要

如果一个主机位于NAT之后,那么在一些特定的情况下它不能直接与其它主机通信。在这些情况下,通信必需要使用中间节点的中继服务。本规范定义了一个叫TURN(Traversal Using Relays around NAT)协议,它允许主机控制中继的操作来和对端交换数据。TURN与其它中继协议不同在于它允许客户端只使用一个中继地址与多个端通信。

TURN协议是做为ICE(Interactive Connectivity Establishment)协议的一部分来设计的。它也可以独立于ICE使用。

本备忘录状态

版权声明

1. 引言

NAT之后的主机有可能想要于其它主机交换数据包,其中一些主机也可能在NAT之后。为此,所涉及的主机可以使用“打洞”技术(见[RFC5128])来尝试发现一个直连的通信链路;也就是一个穿透NAT和路由但是不包含中继的通信链路。

如[RFC5128]和[RFC4787]所述,打洞技术如果双方都在支持不太好的NAT之后,将会失败。例如,如果双方主机位于地址依赖型映射或地址和端口依赖型映射的NAT之后,直连打洞通常就会失败。

当无法找到一个直连链路,就需要一个中间主机来充当报文的中继。这种中继服务器通常部署在公网,为双方都在NAT之后的主机进行数据包中继。

本规范定义了一个名叫TURN的协议,它允许NAT之后的主机(称为TURN客户端)去请求另一个作为中继的主机(称为TURN服务器)。客户端可以驱使服务器与特定的主机(也称对方)进行数据包交互,也能控制如何终止。客户端通过获取服务器上的一个中继传输地址(relayed transport address)来实现这目的。当对端发送一个数据包到中继传输地址的时候,服务器将这个它转给客户端。当客户端发一个数据包到服务器,服务器将它转发给合适的对端,并使用中继传输地址作为源地址。

一个客户端使用TURN必需有与对端交换中继传输地址和获取对端IP和端口(更精确地说,每一个对端的server-reflexive传输地址,见第2节)的方法。如何完成此操作已经超出了TURN协议的范围。一个方法是客户端和对端通过邮件交换此信息。另一个方法是为客户端和对端使用特殊目的的“介绍(introduction)”或“会(rendezvous)”协议(有关更多详细信息,请参见[RFC5128])。

如果TURN和ICE [RFC5245]一起使用,中继传输地址和对端的IP地址和端口都被包括进ICE的candidate信息中,rendezvous协议必需携带这些信息。例如,如果TURN和ICE被用作使用SIP [RFC3261]的多媒体解决方案的一部分,则SIP扮演rendezvous协议的角色,在SIP的消息体中携带ICE的candidate信息。如果TURN和ICE同其它rendezvous协议一起使用,则[MMUSIC-ICE-NONSIP]提供了rendezvous协议必需执行的服务的指南。

尽管NAT设备后的双方主机使用TURN服务器成功建立通信的概率很大,同时为TURN服务器的提供都带来了高额的成本,因为服务器一般都需要大的带宽连接到互联网。因此最好是在直连链路无法找到的情况下使用TURN服务器,ICE将会使用直连打洞技术来查找一个直连链路,并且如果找不到的情况下只会使用一个TURN服务器。

TURN最初是为了支持使用SIP的多媒体会话而发明的。由于SIP支持分叉,TURN上的每一个中继传输地址都支持多个对端;这个特性在其它设计中没有被支持(例如, SOCKS [RFC1928])。 尽管如此,为了保证TURN也适合其它应用程序,本协议也花了大量的心思。

TURN被设计为ICE的NAT穿透方案的一部分。应敦促TURN的实施者调查ICE并认真考虑将之用在他们的应用程序中。尽管TURN可以离开IE单独使用。

TURN是STUN(Session Traversal Utilities for NAT)协议[RFC5389]的一个扩展。绝大多数,尽管不是全部,TURN消息是STUN消息格式。本文的读者应当熟知STUN。

2. 操作概览

本节以一种不规范的形式给出STUN操作的概览。

在一个典型的配置下,TURN客户端连接在一个私有网络[RFC1918]并通过一到多个NAT设备与外网相通。在外网上是一个TURN服务器。互联网的其它地方分布着一个或多个对端想与该TURN客户端通信。这些对端可能在或不在一个或多个NAT设备之后。该客户端将服务器当作中继将数据包发给这些对端,并接收来自这些端面的数据包。

                                        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

                                 Figure 1
                                 图1

图1 展示了一个典型的部署。在该示意图中,TURN客户端和TURN服务器被NAT分割,客户端在NAT的私有网络方,服务器在NAT的公网方。假定这个NAT为一个”bad”NAT设备;例如,它可能是同时限制IP地址和端口的映射类型(见[RFC4787])。

客户端通过客户端的主机传输地址与服务器对话(IP和端口的组合叫传输地址)。

客户端将通过其主机传输地址将消息发送到服务器的TURN服务传输地址(TURN SERVER TRANSPORT ADDRESS)。客户端通过未指定的方式(例如,配置)获得TURN服务器的传输地址,并且这个地址一般会被很多客户端同时使用。

因为客户端在NAT之后,所以服务器看到数据就如同来自于NAT自身的传输地址一样。这个地址也就是客户端的SERVER-REFLEXIVE 传输地址;服务器到客户端的server-reflexive传输地址的数据包会被NAT转发给客户端的主机传输地址。

客户端使用TURN命令在服务器创建并维护一个ALLOCATION。allocation是服务器上的一个数据结构。该结构除了其它信息之外,还包含为该allocation分配的中继传输地址。服务器上的该中继传输地址可以被其它对端用来给该客户端发送数据。一个allocation是被它的中继传输地址唯一标识的。

一旦创建了ALLOCATION,客户端可以通过将应用数据附加到发送到服务器的指示消息上,从而让服务器将数据转发到对端。客户端将应用数据加在发送给服务器的TURN消息里;在服务器端,从TURN消息里提取出应用数据并通过UDP数据报发送给对等方。在反方向,一个对等端可以通过将应用数据放进UDP数据报里发送给此ALLOCATION的中继传输地址(relayed transport address);服务器将此数据封装进一个指示出是来自于哪个对等端的TURN消息,并发送给客户端。因为TURN消息始终含有客户端是与哪一个对等端通信的指示,所以客户端可以使用一个单独的ALLOCTION与多个对等端通信。

当对等端在NAT之后,客户端必需使用server-reflexive传输地址而不是主机传输地址来标识对等端。例如,上例中,向Peer A发送应用数据,客户端必需指定192.0.2.150:32102 (PeerA的 server-reflexive 传输地址) 而不是 192.168.100.2: 49582 (PeerA的主机传输地址)。

服务器上的每一个ALLOCATION都只属于一个单独的客户端,并且有一个仅由该ALLOCATION使用的中继传输地址。因此,当一个数据包到达服务器的中继传输地址,服务器知道这个数据是针对哪个客户端。

客户端可能同时有多个ALLOCATION。

2.1. 传输层

本规范定义的TURN协议,在服务器与对等端之间始终使用UDP。但是本规范允许使用UDP,TCP或基于TCP的TLS在客户端与服务器之间传递TURN消息。

           +----------------------------+---------------------+
           | TURN client to TURN server | TURN server to peer |
           +----------------------------+---------------------+
           |             UDP            |         UDP         |
           |             TCP            |         UDP         |
           |        TLS over TCP        |         UDP         |
           +----------------------------+---------------------+

如果客户端和服务器之间使用TCP 或TLS-over-TCP,则服务器将在和对等端中继数据的时候在这些传输和UDP传输之间转换。

因为本版的TURN协议仅支持在服务器和对等端使用UDP,预计大多数客户端更倾向于在客户端和服务器之间使用UDP。既然如此,一些读者可能会想:为什么还要支持TCP和TLS-over_TCP?

TURN协议支持客户端和服务器之间使用TCP传输是因为一些防火墙被配置成完全阻止UDP。这些防火墙阻止UDP但不阻止TCP,部分原因是TCP节点被防火墙保护的意图属性对于防火墙来说更明显。例如,TCP有三次握手,这清楚表明被保护的节点确实希望建立特定的连接,而于UDP来说防火墙能做的是猜测通过过滤规则的哪些流是需要的。同样的,TCP有明确的连接拆除;而对于UDP防火墙必需使用计时器来猜测该流何时终止。

TURN协议支持在客户端和服务器之间使用TLS- over-TCP是因为TLS提供了TURN默认摘要身份验证之外的安全属性,一些客户端可能希望利用的属性。特别的,TLS为客户端提供了一种用于确认与之对话的服务器是正确的服务器的方法,并为TURN控制消息提供机密性。TURN并不需要TLS,因为其开销高于摘要认证;例如,使用TLS可能意味着大多数的应用数据会被双重加密(一次通过一次TLS,一次确保它在加密的UDP数据报中)。

有一个计划中的扩展用于支持服务器和对等端使用TCP通信 [TURN-TCP]。因此,在服务器和对等端使用UDP的ALLOCATION叫UDP ALLOCATION,当使用TCP是叫TCP ALLOCATION。本规范只描述UDP ALLOCATION。

本规范定义的TURN协议,仅支持IPv4。本规范中的所有IP地址都必需是IPv4地址。有一个支持IPv6和支持在IPv4与IPv6之间中继的计划 [TURN-IPv6]。

在一些TURN的应用程序中,客户端可能在其与服务器通信的主机传输地址上传输非TURN数据包。这是可能发生的,例如,当TURN和ICE一起使用时。在这些情况中,客户端可以通过检查收到数据包的源地址来区分TURN数据包和其它数据包:从TURN服务器来的数据包是TURN数据包。

2.2. ALLOCATIONS

客户端使用一个分配事务在服务器上创建一个 ALLOCATION。客户端发送一个分配请求给服务器,然后服务器回复一个分配成功响应,这个响应包含服务器分配的中继传输地址。客户端可能在分配请求中包含一些用于描述它需要分配的类型的属性(例如,ALLOCATION的生存时间)。因为中继数据会有一安全隐患,服务器需要客户端认证它自己,一般使用STUN协议的长期凭据机制,以表明它已经被授权使用。

一旦分配 了中继传输地址,客户端必需保持ALLOCTION存活。为此客户端周期性地送一个刷新请求到服务器。TURN故意使用一个不同的方法(刷新而不是分配)进行刷新以确保ALLOCATION因为某种原因消失而能通知到客户端。

刷新事务的频率由ALLOCATION的生存期决定。默认的ALLOCATION的生存期是10分钟 – 这个值取得足够长因此刷新对于客户端来说就不会是一个负担,又保证当客户端异常退出时ALLOCATION能及时过期。但是,客户端可以在分配请求中要求更长的生存期,也可以在刷新请求中更改,并且服务器始终在响应中指示实际的生存期。客户端必需在前一个分配或刷新事务的生存期内发出新的刷新事务。一旦客户端不再希望使用一个ALLOCATION,它应当通过一个生存期为0的刷新请求来删除这个ALLOCATION。

客户端和服务器跟踪一个5元组。在客户端,5元组由客户端的主机传输地址,服务器传输地址,客户端与服务器的传输层协议组成。在服务器端,5元组的值除了客户端的主机传输地址被替换成客户端的server-reflexive地址其它都一样,因为这是服务器看到的客户端地址。

客户端和服务器都记住分配请求中的5元组。客户端和服务器的后续消息都使用相同的5元组。这样,客户端和服务器知道索引哪一个ALLOCATION。如果客户端希望分配第二中继传输地址,它必需使用不同的5元组(例如不同的客户端主机地址或端口)创造第二个ALLOCATION。

注意:虽然本文档使用的术语是指5元组,但TURN服务器可以存储任何它喜欢的标识符来达到相同的目的。具体来说,一个实现可能使用文件描述符代替5元组表示的TCP连接。

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |-- Allocate request --------------->|             |             |
    |                                    |             |             |
    |<--------------- Allocate failure --|             |             |
    |                 (401 Unauthorized) |             |             |
    |                                    |             |             |
    |-- Allocate request --------------->|             |             |
    |                                    |             |             |
    |<---------- Allocate success resp --|             |             |
    |            (192.0.2.15:50000)      |             |             |
    //                                   //            //            //
    |                                    |             |             |
    |-- Refresh request ---------------->|             |             |
    |                                    |             |             |
    |<----------- Refresh success resp --|             |             |
    |                                    |             |             |

                                 Figure 2
                                 图2

在图2中,客户端发送一个没有凭据的分配请求到服务器。由于服务器要求所有请求必需使用STUN协议的长期凭据机制进行身份认证,服务器用来有401(未授权)的错误码来拒绝这个请求。客户端重试,这一次包含凭据(未显示)。此时服务器接受这个分配请求并返回一个分配成功响应,包含(除其它外)分配给此ALLOCATION的中继传输地址。稍后,客户端决定刷新这个ALLOCATION,因此发送一个刷新请求到服务器。刷新被服务器接受拼回复刷新成功响应。

2.3. 许可

为减轻企业IT管理员的负担,避免使用公司的防火墙安全机制,TURN包括许可的概念。TURN许可机制仿照了NAT地址限制过滤机制[RFC4787]。

一个ALLOCATION可以有零到多个许可。每个许可由一个IP地址和生存期组成。当服务器从这个ALLOCATION的中继传输地址收到一个UDP数据报时,它首先检查许可单。如果数据报的源IP匹配到一个许可,则这个应用数据就会被转发到客户端,否则就忽略这个数据报。

客户端可以通过CreatePermission请求或ChannelBind请求来安装或刷新一个许可。使用CreatePermission请求可以一次安装或刷新多个许可 – 这对于使用ICE协议的应用程序来说很重要。出于安全的原因,许可只能由被认证的事务来安装或刷新;因此,发送指示和通道数据消息(用来发送数据给对等端)不会安装或刷新任何许可。

注意许可属于一个ALLOCATION的上下文,所以在一个ALLOCATION中添加一个许可或让一个许可失效都不影响到其它ALLOCATION的。

2.4. 发送机制

有两个机制可以用于客户端和对等端使用TURN服务器进行应用数据交换。一个机制使用SendData方法,另一个机制使用通道(channels)。这两种方法的共同点是有能力让客户端在使用一个中继传输地址的情况下与多个对等端进行通信;因此,两个方法都暗含了如下的意思,让客户端指示服务器应该接收哪个对等端数据和让服务器指示客户端数据是从哪个对等端发送的。

发送机制使用SendData指示。Send指示被用于发送从客户端到服务器的应用数据,而Data指示被用于发送从服务器到客户端的数据。

当使用发送机制时,客户端发送一个Send指示到TURN服务器,这个指示包含(a)一个用于指定对等端的(server-reflexive)传输地址的XOR-PEER-ADDRESS属性和(b)一个含有应用数据的DATA属性。当TURN服务器收到Send指示时,它从DATA属性中提取出应用数据并将之通过UDP数据报发送给对等端,并使用中继传输地址作为其源地址。注意没有必要指定中继传输地址,因为它已经隐含在用于Send指示的5元组中了。

在反方向上,UDP数据报到达TURN服务器的中继传输地址会被转换成Data指示,并发送到客户端。这个指示会有一个包含对等端server-reflexive传输地址的XOR-PEER-ADDRESS属性和包含收到的数据的DATA属性。因此中继传输地址唯一标识出一个ALLOCATION,服务器就知道应该把数据发给哪个客户端。

SendData指示不能被认证,因此STUN的长期凭据机制不支持认证所有指示。这不像最初出现的问题那么大,因为客户端到服务器只是到对等端全路径的半程。如果应用程序需要合适的安全性应当加密客户端与对等端发送的数据。

因为Send指示不是认证过的,一个攻击有可能发送假冒的Send指示到服务器,然后这个数据会被转发到对等端。为了部分缓解这种攻击,TURN协议要求客户端在使用Send指示发送数据前先安装一个对等端的许可。

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |                                    |             |             |
    |-- CreatePermission req (Peer A) -->|             |             |
    |<-- CreatePermission success resp --|             |             |
    |                                    |             |             |
    |--- Send ind (Peer A)-------------->|             |             |
    |                                    |=== data ===>|             |
    |                                    |             |             |
    |                                    |<== data ====|             |
    |<-------------- Data ind (Peer A) --|             |             |
    |                                    |             |             |
    |                                    |             |             |
    |--- Send ind (Peer B)-------------->|             |             |
    |                                    | dropped     |             |
    |                                    |             |             |
    |                                    |<== data ==================|
    |                            dropped |             |             |
    |                                    |             |             |

                                 Figure 3
                                 图3

在图3中,客户端已经创建了一个ALLOCATION并准备发送数据到它的对等端。客户端首先通过向服务器发送一个指定Peer A的(server-reflexive)传输地址的CreatePermission请求创建一个许可;如果不这样做,服务器不会中继客户端与服务器之间的数据。接着客户端通过Send指示发送数据到Peer A;服务器提出出应用数据并使用UDP数据报转发到Peer A,并使用中继传输地址作为其源地址。当服务器人中继传输地址收到来自Peer A的UDPovrrn报,则其内容会被放入一个Data指示并转发给客户端。接着,客户端试图与Pe通道er B交换数据;然而,没有为Peer B安装许可,所以来自客户端的Send指示和来自对等端的UDP数据报都会被服务器丢弃。

2.5. 通道

对于一些应用(例如, Voice over IP),附加在应用数据之上的Send指示或Data指示的36字节的开销会极大地增加客户端和服务器的带宽。为了解决这个问题,TURN提供了第二种方式来关联客户端、服务器和特定的对等端之间的数据。

该方法使用一个被称为ChannelData消息的数据包格式。ChannelData消息不使用其它TURN消息使用的STUN头,取而代之的是一个被称为通道号的4字节头。每一个使用中的通道号与特定的对等端绑定,因此用作对等端主机地址的简略表示。

为了绑定一个通道到一个对等端,客户端发送一个ChannelBind请求到服务器,并包含一个未绑定的通道号和该对等端的传输地址。一旦通道绑定,客户端可以使用ChannelData消息发送目的地是对等端的数据到服务器。同样的,服务器可以使用ChannelData消息中继该对等端的数据到客户端。

如果不刷新,通道绑定持续10分钟 – 这个时间要比许可的生存期要长。通道绑定通过发送另一个ChannelBind请求刷新。如许可(但和ALLOCATION不一样)一样,没有明确的方法删除一个通道绑定;客户端必需简单地等待它超时。

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |                                    |             |             |
    |-- ChannelBind req ---------------->|             |             |
    | (Peer A to 0x4001)                 |             |             |
    |                                    |             |             |
    |<---------- ChannelBind succ resp --|             |             |
    |                                    |             |             |
    |-- [0x4001] data ------------------>|             |             |
    |                                    |=== data ===>|             |
    |                                    |             |             |
    |                                    |<== data ====|             |
    |<------------------ [0x4001] data --|             |             |
    |                                    |             |             |
    |--- Send ind (Peer A)-------------->|             |             |
    |                                    |=== data ===>|             |
    |                                    |             |             |
    |                                    |<== data ====|             |
    |<------------------ [0x4001] data --|             |             |
    |                                    |             |             |

                                 Figure 4
                                 图4

图4显示了正在使用中的通道机制。客户端已经创建了一个ALLOCATION并希望给Peer A绑定一个通道。为此,客户端发送一个ChannelBind请求到服务器,指定Peer A的传输地址和通道号(0x4001)。之后,客户端可以将应用数据封装进ChannelData消息发送给Peer A:这被展示为”[0x4001] data”其中0x4001是通道号。当ChannelData消息到达服务器,服务器将之转换到UDP数据报中并发送给Peer A(也就是绑定通道号为0x4001的对等端)。

在反方向上,当Peer A发送一个UDP数据报到中继传输地址,这个UDP数据报在为其ALLOCATION分配的中继传输地址上到达。因为UDP数据报是从Peer A接收,已经有一个通道号分配给它,服务器在将该数据发送给客户端的时候会将其封装进一个ChannelData消息。

一旦一个通道被绑定,客户端可以自由地混合使用ChannelData消息和Send指示。在图中,客户端之后 决定使用Send指示而不是ChannelData消息来发送额外的数据到Peer A。客户端可能决定如此做,例如,它可以使用禁止分片(DONT-FRAGMENT)属性(参考下节)。但是,一旦一个通道被绑定,服务器将会始终使用ChannelData消息,如调用流所示。

注意ChannelData消息只用于客户端已经绑定通道的对等端。在上例中,Peer A已经绑定了一个通道,但是Peer B没有,所以来自和到达Peer B的应用数据将使用Send机制。

2.6. 无特权级的TURN服务器

此版本的TURN旨在让服务器程序可以在通常的操作系统上被实现为不需要特权的能在在用户空间运行的应用程序。这个设计决策是为了便于部署TURN服务器:例如,允许一个TURN服务器集成到一个端到端的应用程序中以便于一个对等端能为另一个对等端提供NAT穿透服务。

此决策对于通过TURN服务器中继数据有如下影响:

2.7. 避免IP分片

2.8. RTP支持

2.9. 服务器的任播发现

3. 术语

4. 一般行为

本节包含对于所有TURN消息的一般处理规则。

TURN是STUN的一个扩展。除ChannelData消息外的所有TURN消息都是STUN格式消息。所有STUN格式消息的基本处理规则在[RFC5389]中描述。这也意味着本文档所有的消息格式和消息处理描述都隐含已经由[RFC5389]的规则前处理过了。

[RFC5389]指明了一个称为长期凭据机制的认证机制。TURN服务器和客户端必需实现这个机制。服务器必需要求所有来自客户端的请求使用此机制进行身份验证,或者使用同等强壮和更强的客户端身份验证机制。

注意长期凭据机制只用在请求中并不能用于指示;因此,TURN中的指示都不会难。如果服务器无路可退验证请求,则服务器管理员必需选择一个realm值用于唯一标识客户端必需使用的用户名和密码的组合,即使客户端多个不同管理员名下的服务器。服务器的管理员可能为每一个客户端选择一个用户名,或者为多个客户端选择一个相同的用户名(例如,为部门或公司的所有客户端)。对于每一个ALLOCATION,服务器分配ALLOCATION时应当遵守[RFC4086]中的随机性建议生成一个新的随机nonce,并在ALLOCATION的生命期内至少每个小时都让nonce过期失效一次。

在初始分配请求之后的所有后续请求都必需使用与创建时相同的用户名。特别的,如果服务器需要使用长期凭据机制,且一个非分配请求通过认证,且5元组标识了一个存在的ALLOCATION,但是该请求使用的username与创建时不同,则该请求必需使用441(错误凭据)错误码来拒绝。

当一个TURN消息从客户端到达服务器,服务器使用消息中的5元组来标识其关联的ALLOCATION。对于所有的TURN消息(包括ChannelData)除了分配请求,如果5元组不能标识一个存在的ALLOCATION,则消息必需通过437 ALLOCATION不匹配错误码来拒绝(如果是一个请求)或直接忽略丢弃(如果是一个指示或一个ChannelData消息)。一个客户端接收到一个分配请求以外的请求的437错误响应就必需假定这个ALLOCATION不存在。

[RFC5389]定义了一系列属性,包括SOFTWARE和FINGERPRINT属性。客户端应当在所有分配和刷新请求中包含SOFTWARE属性,并可能将之包含在其它请求或指示中。服务器应当在所有分配和刷新响应中包含SOFTWARE属性,并可能将之包含在其它响应和指示中。客户端或服务器可能在任何本文定义的STUN格式的消息中包含FINGERPRINT属性。

TURN不使用[RFC5389]中描述的向后兼容机制。

本文定义的TURN,仅支持IPv4。客户端、服务器和所有中继传输地址出现的IP地址都必需使用IPv4地址。

默认情况下,TURN和STUN运行在同样的端口:基于UDP、TCP的TURN使用3478,基于TLS的TURN使用5349。TURN有它自己的服务记录集(SRV): 基于UDP、TCP的为”turn”,基于TLS的为”turns”。SRV过程或ALTERNATE-SERVER过程两者都在第6节描述,可以用于将TURN运行在不同的端口。

为了确保互操作性,一个TURN服务器必需支持客户端和服务器进行UDP传输,并应当支持使用TCP和TLS传输。

当客户端和服务器之间使用UDP传输时,客户端在一个特定的超时周期内没收到一个响应的话会重传请求。因此,服务器可能收到两个(或多个)同样的5元组且同样的事务ID的请求。STUN要求服务器识别这种情况并将之当成幂等(见[RFC5389])请求对待。一些实现可能选择记录所有请求和相应的响应40秒来满足此要求。其它实现可能选择重新处理这个请求并安排这种重新处理返回基本相同的响应。为帮助选择后一种方法的实现(所谓无状态),本规范包含一些如何做的实现注意事项。实现可以自由选择,都能达到相同结果。

当客户端和服务器之间使用TCP传输时,位错误可能会导致TURN数据包中的长度字段损坏,导致接收方失去与传入流中的TURN消息同步。客户端或服务器通过TCP传输检测到一个长序列无效的TURN消息时应当关闭相应的TCP连接以帮助另一端更快地检测出此情况。

为减轻有意或无意的带有有效用户名和密码的拒绝服务攻击,建议服务器对同一时为特定的用户分配的ALLOCATION数量和带宽总量加以限制。服务器应当通过486错误码(Allocaton Quota Exceeded)拒绝可能超过最大允许活动ALLOCATION数量的分配请求,并应当忽略超过带宽定额的应用数据流。

5. ALLOCATIONS

所有的TURN操作都围绕ALLOCATION,所有的TURN消息都与ALLOCATION关联。一个ALLOCATION在概念上由如下状态数据组成:

中继传输地址是由服务器为与对等端通信而分配的传输地址,而5元组描述的是客户端和服务器的通信路径。在客户端,5元组使用客户端的主机传输地址;在服务器,5元组使用客户端的server-reflexive传输地址。

中继传输地址和5元组都对于所有ALLOCATION来说都应该是唯一的,因此这两者之一都可以被用来唯一标识一个ALLOCATION。

认证信息(例如,用户名,密码,realmnonce)被既用来校验后续的请求又被用来计算响应的消息完整性。用户名,realm,和nonce的值是初始经过身份难的分配该ALLOCATION的请求中使用的值,尽管服务器可以在ALLOCATION的生存期内回复438(Stale Nonce)来改变nonce的值。注意,比起显式地存储密码,基于安全的原因,可能对于服务器来说存储密钥更值得,密钥是一个基于用户名,realm,和密码的MD5哈希(见[RFC5389])。

过期时间是ALLOCATION离过期失效剩余的时间,以秒为单位。每一个分配和刷新事务设置这个向下递减到0的定时器。默认情况下,每个分配和刷新事务重置这个定时器到默认600秒(10分钟)的生存期值,但客户端可以在分配和刷新请求中请求不同的值。所有ALLOCATION只能通过刷新请求刷新;发送数据到对等端不会刷新一个ALLOCATION。当一个ALLOCATION过期,与之关联的状态数据可以被释放。

许可单在第8节中描述。通道单在第11节中描述。

6. 创建一个ALLOCATION

服务器上的ALLOCATION是通过分配事务来创建的。

6.1. 发送一个分配请求

客户端通过如下方式构造一个分配请求。

客户端首先取得一个主机传输地址。建议客户端选择当前未使用的传输地址,一般允许所基于的操作系统为新socket选择一个未使用的端口。

客户端接着选取一个客户端和服务器之间的传输协议。传输协议必需是UDP,TCP,或TLS-over-TCP之一。因为本规范仅允许服务器和对等端使用UDP,所以客户端除非有原因要用别的传输协议建议选择UDP。一个选择不同传输协议的原因可能是,客户端通过配置或实验认为它无法通过UDP联系TURN服务器。有关更多讨论,请参阅第2.1节。

客户端通过如下方式选取一个服务器传输地址。客户端收到(可能是通过配置)一个TURN服务器的域名。客户端接着使用[RFC5389]中描述的DNS过程,只是把SRV服务名字从”stun”(或”stuns”)替换 成”turn”(或”turns”,也就是基于TLS的TURN)。例如,为了找到example.com域名里的所有服务,客户端如果想与服务器通过UDP,TCP或TLS-over-TCP与服务器分别通信则执行”_turn._udp.example.com“,”_turn._tcp.example.com“和’_turns._tcp.example.com‘查找。

客户端必需在请求中包含一个REQUESTED-TRANSPORT属性。这个属性指定服务器与对等端的传输协议(注意这不是出现5元组的传输协议)。在本规范中,REQUESTED-TRANSPORT属性永远为UDP。添加这个属性是为了允许将来的扩展指定其它协议。

如果客户端希望服务器初始化ALLOCATION的过期时间字段为其它的值而不是默认值的生存期,则它可能包括一个LIFTETIME属性指定它希望的值。这只是一个请求,且服务器可能选择一个不同的值。注意请求中所有小于默认值的将会被服务器忽略。

如果客户端希望接下来在该ALLOCATION上的一个或多个Send指示中使用DONT-FRAGMENT属性,则客户端 应当在分配请求中包含一个DONT-FRAGMENT属性。这允许客户端测试服务器是否支持该属性。

如果客户端要求中继传输地址的端口是偶数 ,则客户端包含一个EVEN-PORT属性。如果没有该属性,则端口既可能是偶数也也可能是奇数。如果设置了EVEN-PORT属性的R比特位为1,客户端可以请求服务器保留下一个最高端口(在同样的IP地址),以便后续分配。如果R比特位是0,则不发出此类请求。

客户端可能在请求中也包含一个RESERVATION-TOKEN属性以要求服务器为该ALLOCATION使用以前保留的端口。如果包含了RESERVATION-TOKEN属性,则客户端必需忽略EVEN-PORT属性。

一旦构造完成,客户端将此分配请求发送到5元组。

6.2. 接收一个分配请求

当服务器收到一个分配请求,它执行下列检查:

  1. 服务器必需要求请求被验证。必需使用[RFC5389]指定的长期凭据机制验证,除非客户端和服务器同意通过本文档范围之外的某种过程使用另一个机制。
  2. 服务器检查5元组当前是否被一个ALLOCATION使用中。如果是,服务器通过437(Allocation Mismatch)错误拒绝这个请求。
  3. 服务器检查请求中是否包含REQUESTED-TRANSPORT属性。如果不包含包含REQUESTED-TRANSPORT属性或格式错误,服务器使用一个400(Bad Request)错误拒绝该请求。否则,如果包含该请求但是指定了一个UDP之外的协议,则服务器使用442(Unsupported Transport Protocol)错误拒绝该请求。
  4. 请求可能含有DONT-FRAGMENT属性。如果的确含有,但是服务器不支持在发送UDP数据报的时候设置DF比特位为1(见第12节),则服务器将会将分配请求中的DONT-FRAGMENT属性当成未知comprehension-required属性对待。
  5. 服务器检查请求中是否含有RESERVATION-TOKEN属性。如果有,且含有EVEN-PORT属性,则服务器用400(Bad Request)错误拒绝这个请求。否则,检查token是否合法(例如,token在范围内且没有过期且与相应的中继传输地址依然可用)。如果token因为一些原因不合法,服务器用508(Insufficient Capacity)错误拒绝该请求。
  6. 服务器检查请求中是否含有EVEN-PORT属性。如果有,则服务器检查是否能满足这个请求(例如,可以分配一个如下所述的中继传输地址)。如果服务器不能满足这个请求,则用508(Insufficient Capacity)错误拒绝该请求。
  7. 任意时刻,当服务器察觉客户端试图超过一些本地定义的ALLOCATION配额,就可能选择使用486(Allocation Quota Reached)错误拒绝该请求。
  8. 同样的在任意时刻,当服务器希望重定向客户端到另一个服务器,则可能通过300(Try Alternate)错误拒绝客户端的请求。这个错误码及属性的用法参考[RFC5389]规范。

如果所有检查通过,服务器创建ALLOCATION。ALLOCATION的5元组设置为分配请求的5元组,而许可列表和通道列表被初始化为空。

服务器通过下述方法为该ALLOCATION选择一个中继传输地址:

在所有的情况中,服务器应当仅在49152-65535(动态和/或私有端口范围[Port-Numbers])范围内分配端口,除非TURN服务器应用知道,通过某种此处未指定的方式,在同一主机上运行的其它应用程序不会因为TURN服务器分配这个范围外的端口而受到影响。这种情况可以通过在专用的机器上并在TURN服务器运行之前安排好其它应用分配的端口,来满足运行TURN服务器应用程序。在任何情况下服务器不应该在0-1023(已知端口范围)之间分配端口以阻止客户端使用TURN运行标准服务。

注意:略

服务器通过如下方式来确定过期时间的初始值。如果请求中包含LIFETIME属性,则服务器计算客户端提议的生存期和服务器允许的最大的生存期这两者的最小值。如果计算结果比默认生存期大,则服务器使用计算结果作为过期时间字段的初始化值。否则,服务器使用默认的生存期。推荐服务器最大允许的生存期值不大于3600秒(1小时)。服务器实现ALLOCATION的配额或向用户收取费用可能希望使用较小的允许值(可能小到默认生存期)以更快地移出孤儿ALLOCATION(也就是其客户端已经崩溃或终止或由于某种原因客户端连接丢失的ALLOCATION)。此外,请注意每一个成功的刷新请求都会重新计算过期时间,因此,此处计算的值仏生效到第一次刷新请求。

一旦创建了ALLOCATION,服务器回复一个成功响应。成功响应包含:

注意:XOR-MAPPED-ADDRESS属性包含在响应中是为了方便客户端。因此它自己本身不使用这个值,但运行ICE的客户端经常需要这个值并因此避免和一些STUN服务器做额外的绑定事务来获得它。

响应(成功或失败)将被发回5元组上的客户端。

注意:当分配请求是经过UDP发送,[RFC5389]的第7.3.1.节要求服务器处理请求重传的可能,因此重传不会导致创建多个ALLOCATION。实现方法可能使用一种如下称为“无状态堆栈方法”来达到此目的。在初始请求成功创建一个ALLOCATION时为了检测重传,服务器可以保存产生该请求的事务ID和分配的数据并将之与收到相同5元组的分配请求比较。一旦这种请求被检测到,服务器可以停止解析请求并立即生成一个成功响应。当生成这个响应,LIFETIME属性的值可以从ALLOCATION的状态数据中的过期时间字段获取,就算这个值可能与初始返回的生存期值略有不同。更多的,服务器可能需要保存一个在初始响应中返回的保留token的指示,因此这可以在任何重传的响应中返回。

对于没有成功创建一个ALLOCATION的初始请求,服务器可能选择不做任何特别的操作。但是,请注意在极少数的情况下服务器拒绝初始请求但是接受重传请求(因为条件在简短的时间段内已经改变)。如果客户端接收到第一个失败响应,它将忽略第二个(成功)响应并认为ALLOCATION并没有创建。这种情况下创建的ALLOCATION最终将超时,因为客户端将不会再刷新它。此外,如果客户端后续使用不同的事务ID但相同的5元组重度,它会收到一个437(Allocation Mismatch)错误,这会导致它使用一个不同的5元组来重度。服务器可能使用一个小一点的最大生存期值来减少本手册所述的“孤儿”ALLOCATION的生存期。

6.3. 接收一个分配成功响应

如果客户端收到一个分配成功响应,则它必需检查映射地址和中继传输地址是客户端理解并准备处理的地址簇。本规范仅仅覆盖这两地址是IPv4地址的情况。如果这两个地址不是客户端准备处理的地址簇,则客户端必需删除这个ALLOCATION(第7节)并禁止试图在该服务器上创建另一个ALLOCATION,走到它相信不匹配问题已经修复。

IETF目前正在考虑IPv4和IPv6的转换机制,可能导致客户端初始通过IPv6分配请求,但请求通过IPv4到达服务器,反之亦然。

否则,客户端创建它自己的ALLOCATION数据结构的拷贝以跟踪服务器发生的情况。特别的,客户端需要ynwyg服务器返回的实际生存期,而不是发送到服务器的请求里的值。

客户端必需记住用于请求的5元组和用于认证该请求的用户名和密码以确保重新用于他们后续的消息。客户端也需要跟踪它连接的服务器的通道和许可。

客户端可能希望发送中继传输地址到对等端(使用此处未指定的方法)以便对待端能与之通信。客户端可能还希望使用server-reflexive地址来接收ICE处理时的XOR-MAPPED-ADDRESS属性。

6.4. 接收一个分配错误响应