ZYB ARTICLES REPOS

RFC8489(STUN)中文翻译文档

Session Traversal Utilities for NAT (STUN)

翻译

本文翻译的文档为: RFC8489

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

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

点此查看中文文档

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

概要

STUN协议是一个可以被其它协议用来处理NAT穿越的工具。端点可以用它来确定NAT分配给它的IP地址和端口。它既可以被用来检查两个端点之间的连通性,也可以作为一个维护NAT绑定的保活协议。STUN与现有很多的NAT都兼容,不需要它们有任何特殊的处理。

STUN它自身并不是一个NAT穿越的解决方案。相反,它只是一个被用于解决NAT穿越场景下的一个工具。

本文档淘汰RFC 5389。

本备忘录状态

版权声明

1. 引言

此规范中定义的STUN协议,提供一个处理网络地址转换(NAT)的工具。它为端点提供了一种用于确定NAT为其建立的外网IP地址、端口到其内网IP地址、端口映射的方法。它也提供了一个对NAT绑定保活的方法。在一些扩展的帮助下,此协议还可以被用来检查两个端口的连通性[RFC8445]或用于在两个端点之间中转数据包[RFC5766]。

为了保持本协议的工具性质,此规范定义了一个可扩展的数据包格式,定义了基于多个传输协议的操作,并提供了两种身份认证的方式。

STUN旨在被用于一个或多个NAT穿越的解决方案中。这些方案被称为”STUNUsage(STUN Usages)“。每种Usage描述了如何利用STUN来实现NAT穿越。一般的,一个Usage指示什么时候发送STUN消息,该包含什么可选属性,使用什么服务以及要使用什么认证机制。ICE(Interactive Connectivity Establishment)协议[RFC8445]就是STUN的一个Usage。另一个Usage是SIP Outbound协议[RFC5626]。在某些情况下,一个Usage需要对STUN协议进行扩展,STUN的扩展则会以新的方法,属性,或错误响应码的形式出现。STUN Usage的更多信息可以参考第13节。

2. 操作概览

本节仅是描述性的。


                           /-----\
                         // STUN  \\
                        |   Server  |
                         \\       //
                           \-----/




                      +--------------+             Public Internet
      ................|     NAT 2    |.......................
                      +--------------+



                      +--------------+             Private Network 2
      ................|     NAT 1    |.......................
                      +--------------+




                           /-----\
                         // STUN  \\
                        |   Client  |
                         \\       //               Private Network 1
                           \-----/

                 Figure 1: One Possible STUN Configuration
                 图1: STUN的一个可能的结构

如图1所示是一个STUN的可能结构。在个结构下,有两个支持STUN协议的实体(叫STUN代理)。图中下面的代理是连在私有网络1中的客户端。私有网络1通过NAT 1连到私有网络2中,私有网络2又通过NAT 2连到公网。图中最上面的代理是一个位于公网的服务器。

STUN是一个C/S协议。它提供两种事务处理方式。一种是客户端发送请求,服务器返回响应的的请求/响应的事务处理方式。另一种是客户端和服务器都能发送的不会生成响应的指示型事务。两种事务都包含一个随机的96bit的Transaction ID。对于请求/响应式事务,Transaction ID允许客户端将其发送的请求与该请求的响应包相关连;对于指示型,Transaction ID可以作为帮助调式使用。

每个STUN消息都以一个固定的头部开始,头部含有一个方法,一个类别和一个Transaction ID。方法用于指出是各种请求或指示中的哪一种。本规范只定义了Binding这一种方法,但其它的方法预计将会被定义在其它文档中。类别指出这是请求头,还是成功响应,还是错误响应,还是指示。在固定的头部之后有零到多个属性。每个属性都是TLV(Type-Length-Value)扩展,用于为特定的消息传达附加信息。

本文档定义仅定义了一个叫Binding的方法。此方法既可以被用于请求/响应型事务,也可以被用于指示型事务。当被用于请求/响应型事务中的时候,Binding方法可以用来确定NAT为STUN客户端建立的是何种绑定映射。当被用在请求/响应和指示型事务中时,该方法可以被用来保持NAT的绑定映射有效。

在Binding的请求/响应事务中,Binding请求是从客户端发送到STUN服务器的。当Binding请求到达STUN服务器的时候,它可能已经通过了客户端和服务器之间的一个或多个NAT(图1, 有两个这样的NAT)。由于Binding请求通过NAT的时候,NAT会修改数据的源传输地址(也就是源IP地址和源端口)。因此,服务器收到的请求的源传输地址只会是离服务器最近的NAT设备的公网IP地址和端口。这叫做“reflexive transport address(反射传输地址)”。STUN服务器将这个源地址复制到Binding回包的XOR-MAPPED-ADDRESS属性中,并将这个数据包发送回客户端。回传的时候,当数据包会通过一个NAT设备,NAT设备会修改它的IP头里的目的传输地址,而在STUN响应包的XOR-MAPPED-ADDRESS属性中的传输地址则不会被修改。在此情况下,客户端就可以通过询问STUN服务器的方式来得到最外层NAT分配给它的reflexive传输地址。

在一些Usage中,STUN必需与其它协议(如 [RFC8445] 和 [RFC5626])一起多路复用。在这些Usage中,必需有检查并确定它是不是STUN数据包的方法。为此STUN协议在头部中提供三个固定的值的字段。如果这还不够,STUN数据包还可以包含一个FINGERPRINT值,用于进一步区分数据包。

STUN定义了一系列称为机制的可选过程,Usage可以选择是否采用。这些机制包括DNS发现,重定向到备用服务器的技术,用于解决多路复用的fingerprint属性,两种认证方法以及消息完整检查。认证机制围绕用户名、密码和消息完整性。两个认证机制,长期凭证机制和短期凭证机制都定义在本规范中。每个Usage指定允许的机制。

在长期凭据机制中,客户端和服务器共享一个预先配置的用户名和密码并实施摘要质询/响应交换,其设计灵感来源于HTTP [RFC7616]的定义,但是细节不同。在短期凭据机制中,客户端和服务器在STUN交换之前通过一些带外的方法完成用户名和密码的交换。例如,在ICE Usage [RFC8445] 中,两个端点通过带外的信令来交换用户名和密码。这些用于完整性保护,认证请求和响应,没有使用质询和nonce。

3. 术语

4. 定义

STUN Agent: STUN代理是实现了STUN协议的服务器或客户端实体。

STUN Client: STUN客户端是指发送STUN请求和接收STUN响应和STUN指示的实体。STUN客户端也可以发送指示。在本规范中,STUN客户端和客户端意思相同。

STUN Server: STUN服务器是接收STUN请求、指示和发送STUN响应的实体。STUN服务器也可以发送指示。在本规范中,STUN服务器和服务器意思相同。

Transport Address: 传输地址指IP地址和端口号(如UDP、TCP的端口号)的组合。

Reflexive Transport Addess: 反射传输地址是指客户端获得的在外网主机(一般是STUN服务器)看见的能用于标识客户端的传输地址。当有NAT介于客户端和主机之间,反射传输地址代表处于公网的NAT为该客户端分配映射的地址。反射传输地址可以从STUN响应中的MAPPED地址属性(MAPPED-ADDRESS或XOR-MAPPED-ADDRESS)中得到。

Mapped Address: 和反射地址意思一样。保留这个术语是由于历史原因以及MAPPED-ADDRESS和XOR-MAPPED-ADDRESS属性的命名。

Long-Term Credential: 用户名和与之关联的密码代表客户端和服务器共享的秘密。长期凭据通常在订阅者注册一个服务时授予给客户端,直到订阅者离开这个服务或显示地更改凭据。

Long-Term Password: 长期凭据的密码。

Short-Term Credential: 临时用户名和与之相关的密码代表客户端和服务器共享的秘密。短期凭据在STUN协议交换之前通过客户端和服务器的某种协议机制来获取。短期凭据具有明确的基于时间(如5分钟)的时效范围,或基于某个事件(如终止SIP[RFC3261]对话)。短期凭据的时效范围由应用Usage来定义。

Short-Term Password: 短期凭据的密码。

STUN Indication: 不需要接收响应的STUN消息。

Attribute: 属性是STUN定义的一个能添加到STUN消息的类型-长度-值(TLV)对象。属性可以分为两类:comprehension-requiredcomprehension-optional。STUN代理可以安全忽略它们不理解的comprehension-optional属性,但是如果含有不理解的comprehension-required消息则STUN不能成功处理。

RTO: 重传超时(Retransmission Timeout)是定义的一个请求和它的第一次重传的初始时间间隔。

5. STUN消息结构

STUN消息的二进制采用网络序编码(最高位字节优先,即大端序)。传输顺序的细节在[RFC0791]的附录B中有描述。如无其它说明,则数值常量为十进制。

所有STUN消息由20字节的头部和紧跟的零到多个属性组成。STUN头部包含STUN的消息类型,消息长度,幻数和Transaction 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)                  |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 2: Format of STUN Message Header
                  图2: STUN消息头部的格式

每一个STUN消息的最高2bit都必需为0。当STUN和其它协议在同一个端口上多路复用的时候,这一点可以用来区分STUN数据包和其它协议的数据包。

消息类型定义了STUN消息的消息的类别(请求,成功响应,错误响应,指示)和消息方法(主要功能)。尽管有四种消息类别,但在STUN中只有两种事务类型:请求/响应事务(由一个请求消息和一个响应消息组成)和指示事务(由一个单独的指示消息组成)。响应类别分成错误和成功响应,用来帮助快速处理STUN消息。

STUN消息的类型字段进一步分解为如下结构:

                       0                 1
                       2  3  4 5 6 7 8 9 0 1 2 3 4 5
                      +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
                      |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
                      |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
                      +--+--+-+-+-+-+-+-+-+-+-+-+-+-+

                Figure 3: Format of STUN Message Type Field
                图: STUN消息类型字段格式

这里STUN消息类型字段里的比特位是从最高位(M11)直到最低位(M0)来显示的。M11到M0代表了一个12bit的方法编码。C1和C0表示一个2bit的类别编码。类别0b00表示请求,类别0b01表示指示,类别0b10表示成功响应,类别0b11表示错误响应。本规范仅定义了一个方法, Binding。由于方法和类别是正交的,所以对于每一个方法都可能有请求,成功响应,错误响应和指示。扩展定义新的方法必需指明其允许使用哪些类别。

例如,Binding请求的类别为0b00(请求)、方法为(0b000000000001)(Binding),编码后的16bit的值0x0001。Binding响应的类别为0b10(成功响应)、方法为(0b000000000001),编码后的16bit的值0x0101。

​ 注意:这种不幸的编码方式是源于[RFC3489],它没有考虑到指示、成功响应和错误响应对比特域的使用。

幻数字段的值必需是网络序的0x2112A442的固定值。在[RFC3489]中,这个域是Transaction ID的一部分。将幻数放在此处允许服务器探测客户端是否理解[RFC5389]中添加的属性。另外,当STUN和其它协议在同一个端口多路复用的时候,它可以帮助区分STUN和其它协议的数据包。

Transaction ID是一个96bit的标识码,用以唯一标识一个STUN事务。对于请求/响应事务,Transaction ID由STUN客户端选择并填在请求中,而服务器则将这个Transaction ID回显给客户端。对于指示事务,它是由发送指示的代理来选择。它主要应用于将请求与响应关联,当然它在帮助防止某些类型的攻击中也起一点小作用。服务器也用Transaction ID当作一个关键字唯一标识来自所有客户端的每一个事务。因此,Transaction ID必需全局随机地从0 .. 2^96 -1选择,而且应该是密码学级别的随机。重传同样的请求要重用同样的Transaction ID。除非新的请求的所有bit都与先前的请求相同,且发自同一个传输地址到同一个IP地址,否则客户端必需为新的事务选择一个新的Transaction ID。成功和错误响应必需要与其对应的请求带有一样的Transaction ID。即使一个代理在同一个端口上既表现为STUN服务器、又表现为STUN客户端时,它发出的请求中的Transaction ID和收到的响应中的Transaction ID也没有任何关系。

消息长度字段值必需是消息的字节数大小,但其值不包括消息头部的20字节。因为所有STUN属性都会被填充为4字节的倍数,所以此字段的最低2bit始终为0。这也提供了另一个区分STUN和其它协议数据包的方式。

在STUN固定头部部分之后,是零到多个属性。每一个属性都是TLV(Type-Length-Value)编码。编码的详细信息和所有属性本身在第14节中描述。

6. 基本协议过程

这一节定义了STUN协议的基本过程。将描述消息是如何构造的,如何发送,以及收到时如何被处理。也定义了Binding方法的处理细节。本文档的其它章节描述了其它Usage在特定情况下可选择的可选过程。其它文档可能通过添加新的方法、新的属性或新的错误响应码来定义了STUN的新的扩展。

6.1. 构造请求或指示

当构造一个请求或指示消息的时候,代理必需遵守第5节的规则构造头部。而且消息类别必需为”请求”或”指示”,方法必需是Binding或其它文档中定义的方法。

然后代理再根据方法或Usage添加相应的属性。例如,一些Usage可能指示代理使用认证方法(第9节)或FINGERPRINT属性(第7节)。

如果代理准备发送一个请求,它应当(SHOULD)为这个请求添加一个SOFTWARE属性。根据不同的方法,代理可以在指示消息中包含一个SOFTWARE属性。STUN的扩展应当说明SOFTWARE在新的指示中是否有用。注意包含SOFTWARE属性有可能有安全隐患;详细情况可以参考第16.1.2。

对于Binding方法没有认证,除非Usage另有说明,否则它不需要携带属性。

如果知道MTU的话,所有通过UDP或DTLS-over-UDP [Rfc6347]发送的STUN消息应当比路径MTU小。

对于UDP来说,如果不知道路径MTU的话,消息基于IPv4[RFC1122]发送的话应当小于576字节,基于IPv6 [RFC2460]发送的话应当小于1280字节。这个值与IP包总体大小有关。因此,对于IPv4,实际的STUN消息长度应该小于548字节(假定没有IP选项,576减去20字节的IP头,再减去8字UDP头)。

对于DTLS-over-UDP来说如果不知道路径MTU,前一段所述的规则需要调整,以将(13字节)DTLS记录头的大小,消息认证码(MAC)的大小和填充大小纳入考虑。

STUN没有提供处理请求头小于MTU但是响应大于MTU的能力。预计此限制不会成为STUN的问题。MTU限制是应当(SHOULD),而不是必需(MUST),考虑使用STUN本身来探测MTU特性的情况[RFC5780]。也可以参考[STUN-PMTUD]是一个用STUN添加路径MTU发现的框架,该框架用于缺少该机制的协议。除此之外或类似的应用程序,必需遵守MTU限制。

6.2. 发送请求和指示

接下来代理发送请求或指示。本文档指明如何通过UDP,TCP,TLS-over-TCP或DTLS-over-UPD发送STUN消息;在将来可能添加其它传输协议。STUN Usage必需指明使用哪个传输协议,以及代理如何确定接收者的IP地址和端口。第8节描述了一个基于DNS方法来确定一个Usage的服务器可能选择使用的IP地址和端口。

在任何时候,客户端和同一个服务器可能有多个未完成的STUN请求(也就是多个不同Transaction ID的事务在处理中)。对于新的事务请求频率没有其它限制(如ICE中指定的连接检查或运行在TCP之上的STUN),客户端对于同一个服务器应该限制最多有10未处理的请求。

6.2.1. 通过UDP或DTLS-over-UDP发送

当通过UDP或DTLS-over-UDP[RFC7350]来传输STUN时,STUN消息是有可能被网络丢弃的。客户端应用程序自身是通过重传请求消息来实现可靠的STUN请求/响应事务。STUN不重传指示消息,基于UDP和DTLS-over-UDP传输的指示事务不可靠。

一个客户端应当在一个RTO(重传超时 “Retransmission Timeout”)后重传一个STU请求消息,每次重传等待时间翻倍。RTO是RTT的一个估计值,计算方法在 [RFC6298]中有描述,有两个例外。第一,RTO的初始值 应当大于或等于500ms。这个例外情况用“应当”描述,是当其它机制用来得出拥塞阈值(例如ICE为固定速度流定义的)或当STUN被用在知道网络容量的非互联网环境中时。在固定线路访问的链路中推荐500ms。第二,RTO不应四舍五入到最接近的秒。相反,应当保持1ms的精度。与TCP一样,推荐使用Karn算法[KARN87]。当应用到STURN,意味着不应当从产生重传的事务中计算得出RTT的估计值。

客户端应当在完成事务后缓存RTO,并在对同一个服务器的下一次事务的时候用作RTO的初始值(基于IP地址相同)。如果10分钟内对同一个用品没有事务交互则该值应该被视为过期并丢弃。

重传应当直到收到一个响应或者直到完成所有Rc请求发送。Rc应当可配置,并应当默认为7。如果,上次请求之后,过了RTO的Rm倍时间还没有收到响应(如果仅有这最后一个请求真正成功,则提供充足的时间来获得响应),客户端应当认为本事务失败了。Rm应当可配置,并应当默认为16。如果收到一个硬ICMP错误 [RFC1122],通过UDP或DTLS-over-UDP传输的STUN事务应当被认为为失败。例如,假定一个RTO是500ms,请求会在第0ms, 500ms, 1500ms, 3500ms, 7500ms, 15500ms, 和 31500ms被发送。如果客户端在39500ms后依然没收到响应,客户端将会认为事务已经超时。

6.2.2. 通过TCP或TLS-over-TCP发送

6.2.3. 通过TLS-over-TCP和DTLS-over-UDP发送

6.3. 接收STUN消息

本节指明对STUN消息的处理。这里指定的处理方式是针对本规范定义的STUN消息;其它向后兼容的规则定义在第11节中。那些附加的过程是可选的,Usage可以有选择地使用它们。首先,应用一系列与类别无关的处理操作。这在后面的类别处理的子节中有描述。

当一个STUN代理收到一个STUN消息,它首先检查消息是否遵守第5节的规则。它检查首两个比特位是否为0,幻数字段的值是否正确,消息长度是否切合实际,是否支持其方法。再检查对于该方法是否允许其消息类别。如果消息类别是”成功响应”或”失败响应”,则代理继续检查Transaction ID是否与进行中的事务相匹配。如果使用了FINGERPRINT扩展,代理继续检查FINGERPRINT属性是否存在且含有正确的值。如果检测到任何错误,消息将被悄无声息地丢弃。当STUN与其它协议一起多路复用的时候,一个错误可能指出这不是一条真正的STUN消息;在这种情况下,代理应当试着将这条消息当着其它协议来解析。

接下来STUN代理根据Usage所指定的认证机制(参考第9节)来检查。

一旦认证检查完成,STUN代理继续检查消息中的未知的属性和已知但未被期望收到的属性。代理必需忽略掉未知的comprehension-optional属性。代理应当忽略掉已知但未被期望收到的属性。至于未知的comprehension-required属性所引发的一系列操作与接下来讨论的消息类别相关。至此,更进一步的处理取决于请求消息的类别。

6.3.1. 处理请求

如果请求包含一个或多个未知的comprehension-required属性,服务器返回一个包含错误码为420(未知属性 Unknown Attribute)的错误响应并包含一个列出所有未知comprehension-required属性的UNKNOWN-ATTRIBUTES属性

否则,服务器按照方法(Method)或特定Usage的要求继续检查。如果所有检查通过,服务器构造一个如下所述的成功响应。

当基于UDP或DTLS-over-UDP时,当服务器收到一个请求,而这个请求既可能是这次事务的第一条请求,也可能是一个重传请求。服务器必需对重传请求进行响应以保证如下属性:若客户端收到重传请求的响应而不是初始请求的响应,总体上,客户端和服务器的状态等同于,仅初始请求的重传请求的响应包收到,或两个响应都收到(客户端会使用先收到的)。对于服务器来说满足该需求的最简单的方法是记住40秒内所有基于UDP和DTLS-over-UDP的请求的Transaction ID和与之对应的响应。然而这要求服务器保存状态,并且不适用于未认证的请求。另一种方法是重新处理请求并重新生成响应。后一种技术必需应用于请求是幂等(当相同的请求在不影响系统状态的情况下可以安全地重复,则这个请求被认为是幂等的)的情况,并且对于同样的请求生产同样的成功响应。Binding方法是幂等的。注意有相当多各种各样的网络事件可以导致reflexive传输地址改变,导致在不同的成功响应中有不同的mapped传输地址。STUN的扩展必需讨论当服务器不存储事务状态时重传请求的影响。

6.3.1.1. 构造一个成功或错误响应

当构造响应时(成功或错误),服务器遵守第6节的规则。响应中的方法与请求中的方法相同,消息的类别为”成功响应”和”错误响应”。

对于一个错误响应,服务器必需添加一个ERROR-CODE属性,其中包含在上述处理中指定的错误码。错误原因短语不是固定的但是应当与错误码相适应。对于某些错误,会在消息上附加一些属性。这些属性会在描述错误码的地方阐明。例如,对于420(未知属性)错误码,服务器必需包含一个UNKNOWN-ATTRIBUTES的属性。某些认证错误也会导致需要添加属性(参考第9节)。扩展可以定义其它错误 并且/或者 额外的属性。

如果服务器采用认证机制认证了请求,那么服务器应当添加合适的认证属性到响应中(见第9节)。

服务器也会按照方法(Method)或Usage所指定的来添加属性。另外,服务器应当在消息中添加SOFTWARE属性。

对于Binding方法来说,除非Usage特别说明,那么就没有额外的检查需要执行。当构造成功响应时,服务器添加一个XOR-MAPPED-ADDRESS属性到响应中;这个属性包含请求消息的源传输地址。对于基于UDP和DTLS-over-UDP的情况,就是消息的源IP地址和源UDP端口。对于TCP或TLS-over-TCP来说,就是服务器所见的TCP连接的源IP地址和源TCP端口。

6.3.1.2 发送一个成功或错误响应

响应(成功或失败)将会在与请求相同的传输链路上发送。如果请求是通过UDP或DTLS-over-UDP收到的,响应的目的IP地址和目的端口就是该请求消息的源IP地址和源端口,并且响应的源IP地址和源端口与收到请求消息的目的IP地址和目的端口相同。如果请求是通过TCP或TLS-over-TCP收到的,响应将会在收到请求的同一个TCP连接上发送回去。

服务器的响应顺序可以与收到请求的顺序无关。

6.3.2. 处理指示

如果指示包含未知comprehension-required属性,则这个指示将会被丢弃并停止处理。

否则,代理则根据方法(Method)或Usage所指定的进行额外的检查。如果所有检查通过,代理开始处理指示。对于指示来说不会生成它的响应。

对于Binding方法,除非Usage额外指定,否则不需要做其它的检查。代理仅仅接收消息就刷新了中间NAT的Binding。

因为指示不基于UDP或DTLS-over-UDP重传(不像请求),所以在发送代理端没有必要处理指示的重传。

6.3.3. 处理成功响应

如果成功响应包含未知的comprehension-required属性,这个响应被丢弃并认为本次事务失败。

否则,客户端按方法和Usage指定的执行所有额外的检查。如果所有检查通过,客户端再处理这个成功响应。

对于Binding方法,客户端检查XOR-MAPPED-ADDRESS属性在响应中是否存在。客户端再检查指定的地址簇,如果该地址簇不支持,则应当忽略这个属性。如果是一个支持但是未被期望的地址簇(例如,Binding事务通过IPv4发送,但是指定的地址族是IPv6),则客户端可能接受并使用这个值。

6.3.4. 处理错误响应

如果错误响应包含未知的comprehension-required属性,或错误响应中没有ERROR-CODE属性,则本次事务被简单地认为失败。

否则,客户端按认证机制(见第9节)所指定的处理。这可能导致尝试产生一个新的事务。

此处的处理依赖于错误码,方法,Usage;下文是默认的处理规则:

对于任何其它错误码,客户端都应认为事务失败。

7. FINGERPRINT机制

本节为STUN描述一个可选的机制,它可以帮助STUN在与其它协议在同一个传输地址下多路复用的时候从其它协议的数据包中区分STUN消息。本机制是可选的,STUN的Usage必需描述是否使用本机制,且在什么时候使用。FINGERPRINT机制与RFC 3489不后向兼容,所以不能用在需要这种兼容的环境中。

在一些Usage中,STUN消息与其它协议在同一个传输地址上多路复用,如Real-Time Transport Protocol(RTP)。为了应用第6节描述的处理方法,STUN消息必需首先与应用数据包中分离出来。

第5节描述了STUN头部中的3个固定字段可用于此目的。但是在一些情况下,这三个字段可能并不足够。

当使用了FINGERPRINT扩展,一个代理发送给另一个代理的消息中会包含FINGERPRINT属性。第14.7节描述了这个属性在消息中所放的位置和它的属性值。

当代理收到了它认为是STUN的消息,并做了一些附加的基本检查之后,代理接下来检查消息是否含有FINGPRINT属性,并检查它的值是否正确。第6.3节描述了在STUN消息的整体处理过程中何时执行FINGERPRINT检查。这种额外的检查有助代理检测其它协议的看起来像STUN消息的消息。

8. DNS发现服务器

9. 认证和消息完整性机制

本节定义了两个机制,STUN的客户端和服务器可以用这两个机制来提供身份认证和消息完整性。这两个机制也被称为短期凭据机制和长期凭据机制。这两个机制是可选的,每个Usage必需指定是否要使用以及何时使用这两个机制。因此基于使用了哪个Usage客户端和服务器都知道该遵守哪个机制(如果有的话)。例如,一个部署在公网支持ICE的STUN服务器没有身份认证,然而在支持连接检查的代理中的STUN服务器功能将使用短期凭据。第2节中给出了这两个机制的概览。

每个机制指定了使用该机制所需要要的附加处理,这些附加处理扩展了在第6节中指定的处理。附加的处理在三个不同的地方出现:当构造一个消息时,当进行了基本检查后立即接收一个消息时,当详细处理错误响应时。

注意,代理必需忽略MESSAGE-INTEGRITY属性之后除MESSAGE-INTEGRITY-SHA256和FINGERPRINT属性外的所有属性。同样的,如果没有指定MESSAGE-INTERGRITY属性,代理必需忽略MESSAGE-INTEGRITY-SHA256属性后除FINGERPRINT属性外的所有属性。

9.1. 短期凭据机制

短期凭据机制假定,在执行STUN事务之前,客户端和服务器已经通过其它协议交换了用户名和密码形式的凭据。这种凭据是有时间限制的。时间限制由Usage定义。例如,在ICE的Usage[RFC8445]中,两个端点通过带外的信令协商用户名和密码,该用户名、密码在多媒体会话期间适用。

本凭据用于每个请求和许多响应中形成消息完整性检查。没有长期凭据那样的质询和响应;因此,基于凭据本身有时间限制的特性,重放受到了限制。

9.1.1. HMAC Key

对于短期凭据,基于哈希的消息认证码Hash-Based Message Authentication Code(HMAC) 的密钥(key)定义如下:

                    key = OpaqueString(password)

OpaqueString定义在[RFC8265]中。使用UTF-8编码[RFC3629]。

9.1.2. 构造请求或指示

对于一个请求或指示消息,代理必需在消息中包含USERNAME, MESSAGE-INTEGRITY-SHA256和MESSAGE-INTEGRITY属性,除非代理通过外部机制知道双方共同支持哪个消息完整性算法。在这种情况下,除了USERNAME属性外,还必需包含进MESSAGE-INTEGRITY属性或MESSAGE-INTEGRITY-SHA256属性。为MESSAGE-INTEGRITY属性使用的HMAC的计算方法在14.5中描述,为MESSAGE-INTEGRITY-SHA256属性使用的HMAC的计算方法在14.6中描述。注意请求和指示中永远不包含密码。

9.1.3 接收请求或指示

当代理对一个消息完成基本的处理,代理就按如下的顺序对消息进一步检查:

如果所有检查通过,代理继续处理请求或指示。服务器对于一个包含MESSAGE-INTEGRITY-SHA256属性的请求所生成的响应必需包含MESSAGE-INTEGRITY-SHA256属性,该属性使用用于认证该请求的密码进行计算。服务器对于任何一个仅包含MESSAGE-INTEGRITY属性的请求所生成的响应必需包含MESSAGE-INTEGRITY属性,该属性使用用于认证该请求的密码进行计算。这意味着这两个属性中只能有一个能出现在响应中。响应禁止包含USERNAME属性。

如果任何检查失败,服务器禁止在错误响应中包含MESSAGE-INTEGRITY-SHA256、MESSAGE-INTEGRITY和USERNAME属性。因为在这些失败情况下,服务器无法确定计算MESSAGE-INTEGRITY-SHA256和MESSAGE-INTEGRITY属性所需的共享秘密。

9.1.4. 接收响应

客户端查找响应中的MESSAGE-INTEGRITY-SHA256和MESSAGE-INTEGRITY属性。如果存在,且如果客户端在请求中有且仅发送了一个MESSAGE-INTEGRITY或MESSAGE-INTEGRITY-SHA256属性(因为外部9.1.2节中的外部指示或因为9.1.5中定义的后续请求),响应中的算法必需匹配;否则,响应必需被丢弃。

客户端接着用用于请求中同样的密码计算消息完整性,按第14.5节定义的方法计算MESSAGE-INTEGRITY属性,或按14.6节定义的方法计算MESSAGE-INTEGRITY-SHA256属性。如果计算结果与MESSAGE-INTEGRITY或MESSAGE-INTEGRITY-SHA256属性内容相匹配,则响应被认为认证了。如果不匹配,或者如果MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256属性都不存在,接下来的处理依赖于请求是通过可靠还是不可靠的传输链路发送的。

如果请求通过不可靠链路发送,响应必需被丢弃,如同其从未被收到一样。这意味着重传(如果适用)将继续。如果所有收到的响应都被丢弃,协议层必需通知完整性遭到破坏而不是在事务结束时通知超时。

如果请求通过可靠链路发送,响应必需被丢弃,协议层必需立即终止事务并通知完整性遭到破坏。

9.1.5. 发送后续请求

客户端向同一个服务器发送后续请求必需仅发送MESSAGE-INTEGRITY或MESSAGE-INTEGRITY-SHA256属性的其中之一,且必需与收到的初始请求的响应中的属性相匹配。这里的“同一个服务器”指相同的IP地址和端口号,不仅仅是同样的URI或SRV查询结果。

9.2 长期凭据机制

长期凭据机制基于一个在客户端和服务器之间共享的用户名和密码形式的长期凭据。该凭据被认为是长期的,是因其假定它是提供给用户的直到用户不是系统的订阅者的凭据或该凭据被更改。这基本上是提供给用户的传统上的“登录”用的用户名和密码。

因为这些用户名和密码预计在很长的一段时间内有效,重放保护以摘要质询的方式提供。在本机制中,客户端发送一个不提供任何凭据或完整性检查的初始请求。服务器则在拒绝该请求的同时提供一个realm(用来引导用户或代理选择用户名和密码)和一个nonce。nonce用来提供有限的重放保护。它是由服务器选择并以某种形式编码的cookie,用来指示有效期或合法的客户端身份。只有服务器需要知道该cookie的内部结构。接着客户端带上它的username、realm和回显服务器的nonce重试该请求。客户端也会带上本文档定义的消息完整性属性之一的属性,为整个请求,包括nonce,提供HMAC(哈希运算消息认证码,Hash-based Message Authentication Code)。服务器验证nonce并检查消息完整性。如果匹配,则通过认证。如果nonce不再有效,就被认为“过期”,则服务器拒绝该请求,并同时提供一个新的nonce。

在同一个服务器的后续请求中,客户端重用它之前用过的nonce, username, realm和password。这样在服务器的nonce过期之前,后续请求都不会被拒绝。拒绝的话服务器会向客户端提供新的nonce。

注意长期凭据机制不能用于保护指示,因为指示无法被质询。所有的Usage在使用指示的时候必需要么使用短期凭据,要么就省略掉身份认证或消息完整性。

为指示客户端支持本规范,服务器必需在NONCE属性值前加上由 “obMatJos2” 与4个字符连接起的字符串,这4个字符是base64编码的24-bit的STUN安全特性,这些安全特性在18.1节中定义。这24-bit的安全特性集合以3字节编码,其中bit 0为第一字节的最高bit,bit 23为第三字节的最低bit。如果没有安全特性需要使用,则以24bit设置为0的字节数组来编码替代。对于本文档的其余部分,术语”nonce cookie”将指代附加在NONCE属性值之前的完整的13个字符的字符串。

由于长期凭据机制容易受到离线字典攻击,部署应当使用难以猜测的密码。如果凭据不是由用户输入,而是在设备配置期间放置在客户端端设备上的情况下,密码应当有128bit的随机性。如果凭据是由用户输入的情况下,他们应当遵守当前有关密码结构的最佳实践。

9.2.1. Bid-Down攻击预防

本文档介绍两个新的安全特性,可以提供选择算法来用于密码保护的能力,和使用匿名username的能力。为了保持与先前版本的STUN协议向后兼容,这两个功能都是可选的。

这些新功能会受到bid-down攻击,消息路径中的攻击者可以移除这些功能,并强制使用软弱的安全属性。为了防止这类无法探测的攻击,nonce增加了额外的信息。

“nonce cookie”的值会因STUN安全特性的bit位的选择而不尽相同。当本文档在讨论特定的STUN安全特性部门涉及到”nonce cookie”时,应当认为”nonce cookie”中相应的STUN安全功能位置为1。

例如,当使用PASSWORD-ALGORITHMS安全特性(定义在9.2.4节中)时,在”nonce cookie”中相应的”Password algorithms”的比特位(定义在18.1节中)设置成1。

9.2.2. HMAC Key

对于不使用如PASSWORD-ALGORITHM属性所述的不同算法的长期凭据,key是16字节:

                key = MD5(username ":" OpaqueString(realm)
                  ":" OpaqueString(password))

其中MD5在[RFC1321]和[RFC6151]中定义,OpaqueString在[RFC8265]中定义。编码使用UTF-8[RFC3629]。

这16字节是通过将以下五个字段连接起来的结果的MD5哈希值得到的:(1)username, 删除了所有引号和尾随空值,取自USERNAME属性(在这种情况下,已应用OpaqueString);(2)一个冒号;(3)realm,删除了所有引号和尾随空值,并使用OpaqueString处理;(4)一个冒号;(5)password,删除了所有引号和尾随空值,并使用OpaqueString处理。例如,如果username是’user’, realm是’realm’,password是’pass’,则16字节的HMAC key将会是字符串’user:realm:pass’字符串的MD5哈希值,其值为0x8493fbc53ba582fb4c044c456bdc40eb

与长期凭据的一起使用的密钥结构有助于在使用SIP[RFC3261]的系统中部署。通常使用SIP的摘要认证机制的SIP系统实际上不将密码存储在数据库中。相反,它们存储一个名为”H(A1)“的值,该值等于上面定义的key。例如,访机制可以与[RFC5090]中定义的身份认证扩展一起使用。

当使用PASSWORD-ALGORITHM时,使用的key的长度和算法在18.5.1节中描述。

9.2.3. 构造请求

根据9.2.3.1.节的规则处理从客户端发到服务器(如果使用第8节中的DNS过程就是通过hostname来标识,否则通过IP)的初始请求。一旦先前的请求/响应事务成功完成,客户端则发起后续的请求时,它遵守9.2.3.2.节中的规则。构造一个401(未经身份认证)或438(过期Nonce)的错误响应在9.2.5节中涵盖,由于不被视为”后续请求”,因此不使用第9.2.3.2节中描述的规则。这些请求中的每一种都有不同的强制性属性。

9.2.3.1. 初始请求

如果客户端和服务器没有完成一个成功的请求/响应,它必需省略掉USERNAME, USERHASH, MESSAGE-INTEGRITY, MESSAGE-INTEGRITY-SHA256, REALM, NONCE, PASSWORD-ALGORITHMS和PASSWORD-ALGORITHM属性。换句话说,发送的初始请求就像没有应用身份认证和消息完整性。

9.2.3.2. 后续请求

一旦一个请求/响应完成,客户端将被服务器提供一个realm和一个nonce,并选择一个username和password来进行身份认证。客户端应当为后续与服务器的通信缓存username, password, realm和nonce。当客户端发送后续请求,它必需包含具有这些缓存值的USERNAME或USERHASH、REALM、NONCE和PASSWORD-ALGORITHM属性。它必需包含一个MESSAGE-INTEGRITY属性或一个MESSAGE-INTEGRITY-SHA256属性,使用缓存的password来计算它们的方法在14.5节和14.6节中描述。在这两个属性之间的选择,依赖于收到的初始请求的回包的属性。

9.2.4. 接收请求

在服务器完成对请求的基本处理后,它再按如下列表顺序执行检查。注意推荐(RECOMMENDED)的REALM值是STUN服务器的域名:

注意:对于不同源IP或源端口重用NONCE在[RFC5389]中没有明确地禁止。

如果检查通过,服务器继续处理请求。任何由服务器生成的响应必需包含MESSAGE-INTEGRITY-SHA256属性,该属性使用用来认证请求的username和password计算,除非请求如PASSWORD-ALGORITHM如MD5(因为请求即不包含PASSWORD-ALGORITHMS也不包含PASSWORD-ALGORITHM)一样被处理。在这种情况下,必需使用MESSAGE-INTEGRITY属性而不是MESSAGE-INTEGRITY-SHA256属性,而且不应当包含REALM, NONCE, USERNAME, 和USERHASH属性。

9.2.5. 接收响应

如果响应是一个错误响应,且其错误码为401(Unauthenticated)或438(Stale Nonce),客户端必需测试NONCE属性值是否是以”nonce cookie”开头。如果是且”nonce cookie”含有”Password algorithms”的比特位置1的STUN安全特性,但没有PASSWORD-ALGORITHMS属性存在,则客户端禁止以新的事务来重试该请求。

如果响应是一个错误响应,且其错误码为401(Unauthenticated),客户端应当以新的事务重试该请求。该请求必需包含USERNAME或USERHASH,具体包含哪一个由客户端确定,如同从错误响应中为REALM确定合适的username一样。如果”nonce cookie”存在且有”Username anonymity”比特为置1的STUN安全特性,则必需使用USERHASH属性;否则,必需使用USERNAME属性。该请求必需包含从错误响应中拷贝的REALM。该请求必需包含从错误响应中拷贝的NONCE。如果响应包含一个PASSWORD-ALGORITHMS属性,则请求必需包含与之内容相同的PASSWORD-ALGORITHMS属性。如果响应包含一个PASSWORD-ALGORITHMS属性,且该属性含有至少一个被客户端支持的算法,则该请求中必需包含一个PASSWORD-ALGORITHM属性,内容为列表中它支持的第一个算法。如果响应包含一个PASSWORD-ALGORITHMS属性,且该属性没有任何算法是客户端支持的,则客户端禁止使用新的事务重试该请求。如果客户端没有更改上次尝试中使用的USERNAME, USERHASH, REALM或其关联的password,则客户端不得执行此次重试。

如果响应是一个错误响应,且其错误码为438(Stale Nonce),客户端必需使用新该438响应中的新的NONCE来重试请求。此次重试必需也要包含USERNAME或USERHASH,REALM,和MESSAGE-INTEGRITY或MESSAGE-INTEGRITY-SHA256属性。

对于其它响应,如果NONCE属性以STUN安全特性中”Password algorithms”比特位置1的”nonce cookie”开始但PASSWORD-ALGORITHMS不存在,则该响应必需被忽略。

如果该响应是一个错误响应,且其错误码为400(Bad Request),且不既不包含MESSAGE-INTEGRITY或不包含MESSAGE-INTEGRITY-SHA256属性,则该响应必需像未被接收到一样直接忽略掉。这意味着重传(如果适用)将继续。

注意:在这种情况下,400错误响应将永远不会传达给应用层,从而导致超时。

客户端在响应(成功或失败)中查找MESSAGE-INTEGRITY或MEESAGE-INTEGRITY-SHA256属性。如果存在,客户端按14.5或14.6节中所述计算响应消息的完整性,计算时使用与请求中计算时相同的password。如果结果值与MESSAGE-INTEGRITY或MESSAGE-INTEGRITY-SHA256的属性内存相匹配,该响应就可以被认为通过认证。如果不匹配,或MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256属性都不存在,处理方式就依赖于该请求是通过可靠还是不可靠传输发送的。

如果该请求是通过不可靠传输发送的,该请求必需被丢弃,如同它从未被收到一样。这意味着重传(如果适用)将继续。如果收到的所有响应都被丢弃了,那么在事务结束后,协议层必需通告完整性保护遭到破坏,而不是通告超时。

如果请求是通过可靠传输发送的,必需丢弃该响应,且协议层必需立即终止该事务并通告完整性保护遭到破坏。

如果响应包含一个PASSWORD-ALGORITHMS属性,所有后续请求必需使用且仅能使用MESSAGE-INTEGRITY-SHA256来进行身份认证。

10. ALTERNATE-SERVER机制

本节描述STUN的一个机制,该机制允许服务器重定向一个客户端到另一个服务器。本扩展是可选的,并且Usage必需指定是否使用该扩展,且何时使用该扩展。ALTERNATE-SERVER属性带有一个IP地址。

一个服务器使用该扩展,通过对请求消息回复一个错误码为300(Try Alternate)的错误响应来重定向一个客户端到另一个服务器。服务器在错误响应中必需包含至少一个ALTERNATE-SERVER属性,且这个属性至少含有一个地址簇与请求消息的源IP地址簇一样的IP地址。服务器应当在强制添加的ALTERNATE-SERVER属性之后再包含一个额外的ALTERNATE-SERVER属性,这个属性包含请求消息的源IP地址的地址簇以外的IP地址。错误响应消息可能被认证;但是ALTERNATE-SERVER的某些用例中,对响应进行身份认证是不可能也不实用的。如果事务使用TLS或DTLS,如果事务是通过MESSAGE-INTEGRITY-SHA256属性认证,且如果服务器想重定向到一个使用不同证书的服务器,则它必需包含一个ALTERNATE-DOMAIN属性,这个属性包含那个新证书的subjectAltName。MESSAGE-INTEGRITY-SHA256属性上的一系列条件指示事务已经被认证,且客户端实现了此规范,因此可以处理ALTERNATE-DOMAIN属性。

客户端使用这个扩展按如下方式处理300(Try Alternate)错误码。客户端在错误响应中查找ALTERNATE-SERVER属性。如果找到一个,则客户端认为当前事务失败,并重新尝试使用与前一请求相同的传输协议向属性中的服务器发送请求。这个请求,如果已经认证,必需使用与客户端在向执行重定向的服务器的请求中使用的相同的证书。如果传输协议使用TLS或DTLS,则客户端查找一个ALTERNATE-DOMAIN属性。如果找到,这个域必需被用来按[RFC6125]的方式检查证书是否有效。证书必需包含一个类型为 DNS-ID或CN-ID的标识符(最终使用通配符)但不能是SRV-ID或URI-ID。如果ALTERNATE-DOMAIN属性没找到,必需使用用在初始请求中的域来检验证书是否有效。如果客户端已经被重定向到一个它在5分钟内发过请求的服务器,则客户端必需忽略这次重定向并认为该次事务失败。在重定向循环的情况下,这阻止在服务器之间无限ping-pong。

11. 向后兼容RFC 3489

除了在[RFC3489] 的第12节中描述的后向兼容,DTLS必需被禁止与[RFC3489] (又称”经典STUN”)一起使用。任何通过DTLS发送的没有携带幻数(见[RFC5389]的第6节)的请求或指示必需被认为是无效的:对于所有请求必需产生一个500(Server Error)错误响应,并且对于所有指示消息都必需忽略掉。

12. 服务器基本行为

本节定义一个基本,独立的STUN服务器的行为。

从历史来看,经典STUN[RFC3489]仅定义了服务器通过接收和回复STUNBinding请求为客户端提供其反射传输地址。[RFC5389]重新把协议定义成了一个可扩展的框架,并且该服务器的功能变成该文档定义的STUN的唯一Usage。这个STUNUsage又称为”基本STUN服务器(Basic STUN Server)“。

STUN服务器必需支持Binding方法。它可以不使用短期凭据或长期凭据机制。因为认证一个请求要比简单地处理它所付出的代价更高。基于同样的原因它也不应当使用ALTERNATE-SERVER机制。它必需支持UDP和TCP。它可能支持基于TCP/TLS或UDP/DTLS的STUN协议;但是,DTLS和TLS提供最小的安全优势和操作模式。它不需要一个保活机制,因为一个TCP或TLS-over-TCP连接会在Bing事务结束后关闭。它可以使用FINGERPRINT机制但禁依赖它。因为独立的服务器仅运行STUN协议,FINGERPRINT不提供好处。依赖它就会破坏与RFC3489的兼容性,而这种兼容性在一个独立的服务器上是需要的。一个独立的STUN服务器应当如第11节所述支持向后兼容使用[RFC3489]的客户端。

推荐STUN服务器管理员为第8节中描述的服务器提供DNS入口。如果A和AAAA资源记录返回,则客户端可以同时发送Binding请求到IPv4和IPv6地址(如同[RFC8305]指定的),因为Binding请求是幂等的。注意返回的MAPPED-ADDRESS或XOR-MAPPED-ADDRESS属性的值的地址簇与服务器所使用的地址簇不是必需一样的。

一个基本的STUN服务器本身并不是NAT穿越的解决方案。但是,它可以通过STUNUsage作为解决方案的一部分。

13. STUN Usages

STUN自身不是NAT穿越问题的解决方案。但是,STUN定义了一个可以用在大型解决方案的工具。术语“STUN Usage”用在所有将STUN当作一个组件的解决方案中。

一个STUN Usage定义了STUN协议如何实际使用 – 什么时候发送请求,如何处理响应,哪些此处定义的可选的过程(或一个STUN的扩展)将被使用。

一个Usage也定义:

此外,任何STUNUsage必需考虑在该Usage中使用STUN协议的安全隐患。已知许多针对STUN的攻(见本文档的安全注意事项章节),并且任何Usage必需考虑如何失败或减轻这些攻击。

最后一个Usage必需考虑其使用STUN是否是 Unilateral Self-Address Fixing approach to NAT traversal,如果是,解决[RFC 3424]中提出的问题。

14. STUN属性

在STUN头部之后是零到多个属性。每一个属性必需是TLV编码,16bit类型,16bit长度,和值。每个STUN属性必需以32bit边界结束。如上所述,属性的所有字段都是按大端序传输。

      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)                ....
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                    Figure 4: Format of STUN Attributes
                    图4: STUN属性的格式

长度字段必需包含属性值在填充以前部分的长度,以字节为单位。因为STUN以32bit为边界安排属性,所有属性内容不是4字节倍数的都要填充1,2或3字节,因此它们的Value都是4字节的倍数。填充的位必需在发送方设置为0且在接收方忽略。

任何属性类型都可能在一个STUN消息中出现多于一次。除非特别指定,否则,出现的顺序是重要的:仅第一次出现需要接收方处理且任何重复项都可能会被接收都忽略。

为了让本规范未来版本在需要的情况下添新属性,属性空间被分隔成两个区段。属性类型在0x0000和0x7FFF之间的是comprehension-required属性,对这些类型如果STUN代理不理解就不能成功处理。属性类型在0x8000和0xFFFF之间的是comprehension-optional属性,对这些类型如果STUN代理不理解,可以直接忽略。

STUN属性类型集合由IANA维护。初始集合由本规范定义,可以在第18.3节中找到。

本节剩下的部分描述了本规范定义的多种属性的格式。

14.1. MAPPED-ADDRESS

MAPPED-ADDRESS属性标识一个客户端的反射传输地址。它包含一个8bit的地址簇和16bit的端口号,紧接着一个固定长度值代表IP地址。如果地址簇是IPv4则地址必需是32bit。如果地址簇是IPv6,则地址必需是128bit。所有字段都必需是网络序。

MAPPED-ADDRESS属性的格式如下:

      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 0 0 0 0 0 0|    Family     |           Port                |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                 Address (32 bits or 128 bits)                 |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

               Figure 5: Format of MAPPED-ADDRESS Attribute
               图5: MAPPED-ADDRESS属性的格式

地址簇使用如下值:

0x01: IPv4

0x02: IPv6

MAPPED-ADDRESS的头8个bit必需被置0且接收方必需忽略它。这些比特位在这里是为了让参数以32bit边界对齐。

这个属性仅用于服务器向后兼容[RFC3489]客户端。

14.2 XOR-MAPPED-ADDRESS

XOR-MAPPED-ADDRESS属性除了反射传输地址被异或(XOR)混淆过外与MAPPED-ADDRESS属性是等价的。

XOR-MAPPED-ADDRESS属性的格式如下:

      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 0 0 0 0 0 0|    Family     |         X-Port                |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                X-Address (Variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

             Figure 6: Format of XOR-MAPPED-ADDRESS Attribute
             图6: XOR-MAPPED-ADDRESS属性的格式

Family代表IP地址的地址簇,它的编码与MAPPED-ADDRESS的Family字段是一样的。

X-Port通过幻数的高16bit和反射传输端口异或计算得到。如果IP地址簇是IPv4,则X-Address是通过将反射传输IP与幻数异或得到。如果IP地址簇是IPv6,则X-Address是反射传输IP地址通过和幻数与Transaction ID相连接的值进行异或运算得出的。在所有情况下,异或操作的输入都是按网络序(也就是说会被按网络序编码进消息中)。

编码与处理该属性前8bit值的规则,处理该属多次出现的规则,处理地址簇的规则与MAPPED-ADDRESS一致。

注意:XOR-MAPPED-ADDRESS和MAPPED-ADDRESS仅仅在它们编码传输地址的方式上有不同。前者通过和幻数异或,后者通过直接按其二进制编码。RFC3489初台仅指定了MAPPED-ADDRESS。但是,实际部署中发现,一些NAT设备会重写含有NAT外网IP地址的32bit二进制负载,例如STUN协议的MAPPED-ADDRESS属性,这些应用层(Application Layer Gateway)网关虽然出于善意,但是提供了具有误导的功能。这种行为干扰了STUN的操作,也导致了STUN消息完整性检查的失败。

14.3. USERNAME

USERNAME属性用于消息完整性检查。它标识了用于消息完整性检查的用户名和密码组合。

当USERNAME包含认证用户名的时候其长度不固定。它包含的内容必需少于509字节且必需经过OpaqueString[RFC8265]处理过的UTF-8编码[RCF3629]。

一个符合兼容[RFC5389]要求的实现必需支持解析小于或等于763个八位字节的UTF-8编码序列。

注意:[RFC5389]错误地引用了[RFC2279]中的UTF-8定义。[RFC2279]假定每个字符最多使用6个八位字节编码。[RFC2279]已经被[RFC3629]取代,后者允许对每个字符最多仅用4个八位字节编码,与Unicode 2.0和ISO/IEC10646中的更改一致。

注意:本规范使用OpaqueString而不是UsernameCasePreserved来处理用户名字符串是为了提升与已部署密码存储的兼容性。许多密码用于HTTP和SIP的数据库都是以摘要的形式存储用户名:REALM:密码的MD5哈希值,而不是直接存储明文。在[RFC3489]中,对于SIP和HTTP相对于禁止非空格的ASCII控制字符没有对用户名和密码预处理,为可能的扩展性则STUN被设计成与现存的数据库兼容。下一代的STUN规范[RFC5389],使用SASLprep[RFC4013] strinprep [RFC3454]来预处理用户名和密码。SASLprep使用Unicode Normalization Form KC (Compatibility Decomposition, followed by Canonical Composition) [UAX15]和禁止多个控制,空格和非文本弃用或不合适的代码点。PRECIS框架[RFC8264]淘汰了stringprep。PRECIS处理用户名和密码使用Unicode Normalization Form C (Canonical Decomposition, followed by Canonical Composition)。然而有一些不同的用户名字符串在HTTP摘要可能和单个通过OpaqueString处理的STUN用户名一样的例子,但这些例子十分不一样且能轻易发现和改正。使用UsernameCasePreserved,一个合法的用户名在HTTP摘要下将更有可能与它们处理的形式不同(特别的当用户名包含双向文本和兼容形式)。操作将在未来进一步限制允许的用户名中的码点以避免有问题的字符。

14.4. USERHASH

USERHASH属性是用来在支持用户匿名时替换USERNAME的属性。

USERHASH的值长度固定为32字节。用户名必需经过OpaqueString[RFC8265]处理,且realm必需在哈希之前通过OpaqueString[RFC8265]处理。

客户端计算用户名哈希值的方式如下:

userhash = SHA-256(OpaqueString(username) ":" OpaqueString(realm))

14.5. MESSAGE-INTEGRITY

MESSAGE-INTEGRITY属性含有一个STUN消息的HMAC-SHA1 [RFC2104]。MESSAGE-INTEGRITY属性可以在任何消息类型中出现。因为它使用SHA-1哈希,所以HMAC长度将会是20字节。

HMAC的密钥与使用的凭据机制有关。第9.1.1节定义了短期凭据机制的私钥,第9.2.2节定义了长期凭据机制的私钥。其它凭据机制必需定义给HMAC使用的私钥。

HMAC的输入文本是STUN消息,包含MESSAGE-INTEGRITY属性前的所有内容。STUN消息头部的长度字段将调整为指向MESSAGE-INTEGRITY属性末尾。MESSAGE-INTEGRITY属性的值被设置为了个dummy值。

一旦执行了计算,就可以填写MESSAGE-INTEGRITY属性的值,并且STUN头部的长度也应改为正确的值 – 整个消息体的长度。同样的,当校验MESSAGE-INTEGRITY时,STUN头部的长度字段必需被修改指向最后MESSAGE-INTEGRITY属性的前面,以通过STUN消息中MESSAGE-INTEGRITY前面的内容计算HMAC。这样的调整是必需的当属性例如FINGERPRINT和MESSAGE-INTEGRITY-SHA256出现在MESSAGE-INTEGRITY之后。参考[RFC5769]获得这种计算的例子。

14.6. MESSAGE-INTEGRITY-SHA256

MESSAGE-INTEGRITY-SHA256属性含有一个STUN消息的HMAC-SHA256 [RFC2104]。MESSAGE-INTEGRITY-SHA256属性可以出现在任何STUN消息类型中。MESSAGE-INTEGRITY-SHA256属性含有一个STUN消息的HMAC-SHA-256 [RFC2104]的初始部分。这个值最多有32字节,但是这必需至少有16字节且必需是4字节的倍数。除非STUNUsage特别说明截断允许,否则这个值应当被按32字节填满。STUNUsage可能指定一个大于16字节的最小长度。

HMAC的私钥与使用的凭据机制有关。HMAC的密钥与使用的凭据机制有关。第9.1.1节定义了短期凭据机制的私钥,第9.2.2节定义了长期凭据机制的私钥。其它凭据机制必需定义给HMAC使用的私钥。

HMAC的输入文本是STUN消息,包含MESSAGE-INTEGRITY-SHA256属性前的所有内容。STUN消息头部的长度字段将调整为指向MESSAGE-INTEGRITY-SHA256属性末尾。MESSAGE-INTEGRITY-SHA256属性的值被设置为了个dummy值。

一旦执行了计算,就可以填写MESSAGE-INTEGRITY-SHA256属性的值,并且STUN头部的长度也应改为正确的值 – 整个消息体的长度。同样的,当校验MESSAGE-INTEGRITY-SHA256时,STUN头部的长度字段必需被修改指向最后MESSAGE-INTEGRITY属性的前面,以通过STUN消息中MESSAGE-INTEGRITY-SHA256前面的内容计算HMAC。这样的调整是必需的当属性例如FINGERPRINT出现在MESSAGE-INTEGRITY-SHA256之后。参考Appendix B.1获得这种计算的例子。

14.7. FINGERPRINT

FINGERPRINT属性可能在所有的STUN消息中存在。

它的值是通过STUN消息FINGPRINT属性前(但不包括该属性)的内容用CRC-32计算得出,并最终与32bit值0x5354554e异或得到。(异或操作确保FINGERPRINT测试在一个包含应用层协议生成的CRC-32数据包上不会报错。)这个32bit CRC值定义在ITU V.42 [ITU.V42.2002],它有一个产生多项式:x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1。参考[RFC1952]第8节的CRC-32示例代码。

如果存在,FINGERPRINT属性必需是消息体中最后一个属性,因此它会出现在MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256之后。

FINGERPRINT可以帮助从其它协议中区分出STUN数据包。见第7节。

和MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256一起FINGERPRINT属性的CRC值覆盖了STUN消息头中指定的长度。因此,在计算CRC之前,这个值必需正确且将CRC属性算进消息体长度。当在一个消息中使用FINGERPRINT属性时,这个属性在消息中是一个dummy值;然后计算CRC,然后更新这个属性的值。如果MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256也存在,则必需在计算CRC之前填入正确的消息完整性校验值,因为CRC是在MESSAGE-INTEGRITY和MESSAGE-INTEGRITY-SHA256属性基础上计算的。

14.8. ERROR-CODE

ERROR-CODE属性用在错误响应消息中。它含有一个数值在300到699之间的错误码和一个UTF-8 [RFC3629]编码的文本原因短语,它与分配给SIP [RFC3261]和HTTP [RFC7231]的错误码和含义一致。原因短语主要用作诊断目的,它可以是任何与错误码相关的字符串。为已经定义的错误码推荐的原因短语包含在IANA注册的错误码中。原因短语必需是适于128字符(可以在编码时长达509,解码时长达763字节)的UTF -8编码[RFC3629]序列。

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           Reserved, should be 0         |Class|     Number    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Reason Phrase (variable)                                ..
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                 Figure 7: Format of ERROR-CODE Attribute
                 图7: ERROR-CODE属性格式

为了便于处理,错误码(百位数)的类别按图7所示分别从余下的位中编码。

Reserved bits是为了32bit边界对齐,应当为0。接收者必需忽略这些位。错误码的百位代表类别。其值必需在3到6之间。Number代表100以内的二进制编码的错误码,所以它的值必需在0到99之间。

错误码以及与之推荐的相应的原因短语定义如下:

注意:对于一个300响应生成的消息完整性不正确会允许线路上的攻击者篡改300响应,因此会导致接下来的STUN消息被发送到受害者。

14.9. REALM

REALM属性可能存在于请求和响应中。它含有如[RFC3261]所描述的满足”realm-value”语法的文本,但不含有双引号和包围它的空白字符。也就是说。它是一个未被引号引起来的 realm-value(因此是qdtext和quoted-pair序列)。它必需是一个UTF-8编码[RFC3629]的少于128个字符(可以在编码时长达509字节,解码时长达763字节)的序列且必需被OpaqueString[RFC8265]处理过。

当REALM属性出现在一个请求,它表明长期凭据被用于认证。在一些错误响应中出现表示服务器想要客户端使用长期凭据放在realm中来进行认证。

14.10. NONCE

NONCE属性可能存在请求和响应中。它包含一个定义在[RFC3261]中的qdtext和quoted-pair序列。注意这意味着NONCE属性将不会包含两端的引号。NONCE属性必需少于128个字符(可以在编码时长达509字节,解码时长达763字节)。为服务器选择NONCE值的指南见第[RFC7616]的第5.4节。

14.11. PASSOWRD-ALGORITHMS

PASSWORD-ALGORITHMS属性可能存在于请求和响应中。它含有服务器用于派生长期密码的算法列表。

算法集合由IANA管理维护。初始算法集体由本规范定义在第18.5节。

这个属性包含一系列算法号和可变长参数。算法号是一个定义在第18.5节中的16bit数字。参数由16bit的参数长度开始(在填充之前),紧接着指定的该算法的每一个参数。参数按32bit边界对齐填充,如同属性一样。

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |         Algorithm 1           | Algorithm 1 Parameters Length |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm 1 Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |         Algorithm 2           | Algorithm 2 Parameters Length |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm 2 Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                             ...

             Figure 8: Format of PASSWORD-ALGORITHMS Attribute
             图8: PASSWORD-ALGORITHMS属性格式

14.12. PASSWORD-ALGORITHM

PASSWORD-ALGORITHM属性仅存在于请求中。它包含服务器必需用于从长期密码派生私钥的算法。

算法集合由IANA管理维护。初始算法集体由本规范定义在第18.5节。

这个属性包含一个算法号和可变长度的参数。算法号是一个定义在第18.5节中的16bit数字。参数由16bit的参数长度开始(在填充之前),紧接着指定的该算法的每一个参数。参数按32bit边界对齐填充,如同属性一样。同样的,填充的bit位必需在发送方被设置为0且接收方必需忽略掉。

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          Algorithm           |  Algorithm Parameters Length   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

             Figure 9: Format of PASSWORD-ALGORITHM Attribute

14.13. UNKNOWN-ATTRIBUTES

UNKNOWN-ATTRIBUTES属性仅存在于ERROR-CODE属性为420(Unknonw Attribute)的错误响应中。

这个属性包含一系列16bit值,每一个代表一个服务器不认识的属性类型。

      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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Attribute 1 Type         |       Attribute 2 Type        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Attribute 3 Type         |       Attribute 4 Type    ...
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

             Figure 10: Format of UNKNOWN-ATTRIBUTES Attribute
             图10: UNKNOWN-ATTRIBUTES属性的格式

注意:在[RFC3489]中,通过重复最后一个属性这个字段被填充到32(位?字节?)。在本规范的这个版本中,取代的是通用的填充属性的规则。

14.14. SOFTWARE

SOFTWARE属性包含一个发送该消息的代理使用的软件的文本说明。客户端和服务器都使用它。它的值应当包含制造商和版本号。该属性对协议的操作没有影响,仅作为一个工具用于诊断和调试。SOFTERWARE是可变长度。它必需是一个UTF-8编码[RFC3629]的少于128个字符(可以在编码时长达509字节,解码时长达763字节)的序列。

14.15. ALTERNATE-SERVER

转移服务器代表一个转移的传输地址标识一个客户端应当尝试的不同的STUN服务器。

它是按MAPPED-ADDRESS相同的方法编码,因此通过IP地址引用单个服务器。

14.16. ALTERNATE-DOMAIN

转移域表示当使用TLS和DTLS时验证ALTERNATE-SERVER属性中的IP地址的域名。

ALTERNATE-DOMAIN属性的长度不固定。它必需是一个合法的小于等于255个ASCII字符的DNS名字[RFC1123] (包括 A标签 [RFC5890])。

15. 操作考虑

STUN可能被用于任播地址,但是仅用在不需要认证的STUNUsage且基于UDP的地方。

16. 安全考虑

17. IAB考虑

18. IANA考虑

18.1. STUN安全特性注册表

STUN安全特性集合定义了24bits的标志。

IANA创建了一个新的注册表,其中包含受9.2.1节中描述的Bid-Down攻击预防机制保护的STUN安全特性。

初始安全特性如下:

Bit 0: Password algorithms 密码算法

Bit 1: Username anonymity 用户名匿名

Bit 2-23: 未分配

从位的最高位开始分配,因此Bit 0是在最左侧的bit,Bit 23是最右侧的bit。

新的安全特性由Standards Action [RFC8126] 来分配。

其余小节,略

19. 自RFC 5389的改变

本规范淘汰了[RFC5389]。本规范与RFC 5389有如下不同:

20. References

Appendix A. C Snippet to Determine STUN Message Types

Appendix B. Test Vectors