我是靠谱客的博主 奋斗裙子,最近开发中收集的这篇文章主要介绍STUN协议简要介绍,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

转载:https://blog.csdn.net/qq_32523587/article/details/103621017

参考:https://www.rfc-editor.org/rfc/rfc5766.html  STUN/TURN

         https://www.rfc-editor.org/rfc/rfc5389.html

STUN协议在RFC5389中被重新命名为Session Traversal Utilities for NAT,即NAT会话穿透工具。在这里,NAT会话穿透工具被定位为一个用于其他解决NAT穿透问题协议的协议。它可以用于终端设备检查由NAT分配给终端的IP地址和端口号。同时,它也被用来检查两个终端之间的连接性,好比是一种维持NAT绑定表项的保活协议。STUN可以用于多种NAT类型,并不需要它们提供特殊的行为。

STUN本身不再是一种完整的NAT穿透解决方案,它相当于是一种NAT穿透解决方案中的工具。这是与RFC3489/STUN版本相比最重要的改变。

目录

1、STUN简介

2、STUN定义

3、STUN消息结构

4、STUN基本协议流程

4.1、生成请求或指示

4.2、发送请求或指示

4.3、接收STUN消息

4.4、FINGERPRINT机制

4.5、认证和消息完整性机制

5、STUN属性

5.1、MAPPED-ADDRESS

5.2、XOR-MAPPED-ADDRESS

5.3、USERNAME

5.4、MESSAGE-INTEGRITY

5.5、FINGERPRINT

5.6、ERROR-CODE

5.7、REALM

5.8、NONCE

5.9、UNKNOWN-ATTRIBUTES

5.10、SOFTWARE

5.11、ALTERNATE-SERVER


 

1、STUN简介

一种可能的STUN配置如图1所示。在这种配置中,有两个实体(称为STUN代理)实现STUN协议。图中较低的代理是客户端,它连接到专用网络1。该网络通过NAT 1连接到专用网络2。专用网络2通过NAT 2连接到公共互联网。图中的上层代理是服务器,位于公共互联网上。

STUN是一种client-server协议。它支持两种类型的事务。一种是request/response事务,其中客户端向服务器发送请求,服务器返回响应。第二种是指示事务,其中代理(客户端或服务器)发送不产生响应的指示。这两种类型的事务都包括一个事务id,它是随机选择的96位数字。对于request/response事务,此事务id允许客户端将响应与生成它的请求相关联;对于指示,事务id作为调试辅助。

所有STUN消息都以包含方法、class和事务id的固定头开始。该方法指示这是各种请求或指示中的哪一个;本规范只定义了一种方法,Binding,但是其他方法也将在其他文档中定义。该class指示这是请求、成功响应、错误响应还是指示。固定报头之后是零个或多个属性,这些属性是类型长度值扩展,为特定消息传递附加信息。

该文档定义了一个名为Binding的方法。Binding 方法既可以用于request/response事务,也可以用于指示事务。当在request/response事务中使用时,Binding方法可用于确定NAT分配给STUN客户端的特定“binding”。当在request/response或指示事务中使用时,Binding方法也可以用来保持这些"bindings"有效。

在Binding request/response事务中,Binding请求从STUN客户端发送到STUN服务器。当Binding请求到达STUN服务器时,它可能已经通过STUN客户端和STUN服务器之间的一个或多个NATs (在图1中,有两个这样的NATs)。当Binding请求消息通过NAT时,NAT将修改数据包的源传输地址(即源IP地址和源端口)。因此,服务器收到的请求的源传输地址将是最靠近服务器的NAT创建的公共IP地址和端口。这被称为反射传输地址。STUN服务器将源传输地址复制到STUN Binding响应中XOR-MAPPED-ADDRESS属性中,并将绑定响应发送回STUN客户端。当这个数据包通过NAT返回时,NAT将修改IP报头中的目的传输地址,但是STUN响应主体中XOR-MAPPED-ADDRESS属性中的传输地址将保持不变。通过这种方式,客户端可以了解最外面的NAT相对于STUN服务器分配的反射传输地址。如下图:

在某些应用中,STUN必须与其他协议复用(例如,[MMUSIC-ICE], [SIP-OUTBOUND])。在这些用法中,必须有一种方法来检查数据包并确定它是否是STUN数据包。STUN在STUN报头中提供了三个具有固定值的字段,可用于此目的。如果这还不够,那么STUN包也可以包含FINGERPRINT值,该FINGERPRINT值可以进一步用于区分包。

STUN定义了一组可供用户决定使用的可选过程,称为机制。这些机制包括DNS发现、到备用服务器的重定向技术、用于解复用的fingerprint属性以及两次身份验证和消息完整性交换。认证机制围绕用户名、密码和消息完整性值的使用。本说明书中定义了两种认证机制,长期凭证机制和短期凭证机制。每个用法都指定了该用法允许的机制。

在长期凭据机制中,客户端和服务器共享预先设置的用户名和密码,并执行摘要式质询/响应交换,其灵感来源于(但细节不同于)为HTTP [RFC2617].定义的质询/响应交换。在短期凭证机制中,客户端和服务器在STUN交换之前通过某种带外方法交换用户名和密码。例如,在ICE用法中,两个endpoints使用带外信令来交换用户名和密码。这些用于完整性保护和认证请求和响应。没有使用挑战或随机数。

2、STUN定义

STUN代理:  STUN代理是实现STUN协议的实体。该实体可以是STUN客户端或STUN

                     服务器。

STUN客户端:  STUN客户端是发送STUN请求并接收STUN响应的实体。STUN客户端

也可以发送指示。在本规范中,术语STUN client和client是同义词。

STUN服务器:  STUN服务器是接收STUN请求并发送STUN响应的实体。STUN服务器

                       也可以发送指示。在本规范中,术语STUN server和server是同义词。

传输地址:      IP地址和端口号(如UDP或TCP端口号)的组合。

反射传输地址:  客户端获知的传输地址,它将客户端标识为IP网络上的另一台主机,通常

                           是STUN服务器。当客户端和另一台主机之间存在NAT时,反射传输地址表示NAT公共端分配给客户端的映射地                               址。反射传输地址从STUN响应中的映射地址属性(MAPPED-ADDRESS 或XOR-MAPPED-ADDRESS)中获取。

映射地址:  与反射地址的含义相同。该术语仅出于历史原因以及MAPPED-ADDRESS 和

                 XOR-MAPPED-ADDRESS属性的命名而保留。

长期凭据:  代表客户端和服务器之间共享secret的用户名和相关密码。长期凭证通常在订阅者注册服务时授予客户端,并持续到                      订 阅者离开服务或明确更改凭证为止。

长期密码:  来自长期凭据的密码。

短期凭证:  代表客户机和服务器之间共享secret的临时用户名和相关密码。STUN交换之前,通过客户端和服务器之间的某种协                        议机制获得短期凭证。短期凭证具有明确的时间范围,其可以基于特定的时间量(例如5分钟)或事件(例如SIP对话的终                        止)。短期凭证的具体范围由应用程序使用情况来定义。

短期密码:  短期凭据的密码组件。

STUN指示:  没有收到回应的STUN信息。

Attribute:   STUN术语,表示可以添加到STUN消息中的Type-Length-Value (TLV)对象。属性分为两种类型:需要理解和可选理                          解。STUN代理可以安全地忽略理解-他们不理解的可选属性,但是如果消息包含不理解的理解-必需属性,则无法成功                    处理该消息。

RTO:  重传超时,它定义了从发送请求到第一次重传请求之间的初始时间段。

3、STUN消息结构

所有STUN消息必须以一个20字节的报头开始,后跟0个或多个属性。STUN头包含STUN消息类型、Magic cookie、事务id和消息长度

每个STUN消息的最高有效2位必须为零。当STUN与同一端口上的其他协议多路复用时,这可用于区分stun数据包和其他协议。

消息类型:  定义了STUN消息的消息class(请求、成功响应、失败响应或指示)和消息方法(主要功能)。尽管有四个消息class,STUN中只有两种类型的事务:请求/响应事务(由请求消息和响应消息组成)和指示事务(由单个指示消息组成)。响应class分为错误和成功响应,以帮助快速处理STUN消息。

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

这里,消息类型字段中的位显示为最高有效位(M11)到最低有效位(M0)。M11至M0表示该

方法的12位编码。C1和C0表示该类的2位编码。00 class是请求,01 class是指示,10 class是成功响应,11 class是错误响应。这个规范定义了一个单一的方法,Binding。方法和class是正交,因此对于每个方法,请求、成功响应、错误响应和指示对于该方法都是可能的。定义新方法的扩展必须指出该方法允许哪些class。

例如, Binding请求的class=00 (request)和method = 000000000001(Binding),并编码为0x0001的前16位。绑定响应的class=10(成功响应)和method = 000000000001,并编码为前16位0x0101。

注意:这种不幸的编码是由于[RFC3489]中没有考虑使用比特字段编码指示、成功和错误的值分配造成的。

Magic cookie:  必须按网络字节顺序包含固定值0x2112a442。在RFC 3489中,此字段是事务id的一部分;将magic cookie放在这个位置允许服务器检测客户机是否理解在这个修订的规范中添加的某些属性。此外,当STUN与同一端口上的其他协议多路复用时,它有助于区分STUN包和其他协议包

事务ID:  是一个96位标识符,用于唯一标识STUN事务。对于请求/响应事务,事务ID由STUN客户端为请求选择,并由服务器在响应中回显。对于指示,它由发送指示的代理选择。它主要用于将请求与响应相关联,尽管它在帮助防止某些类型的攻击方面也起着很小的作用。服务器还使用事务ID作为密钥,在所有客户端中唯一标识每个事务。因此,事务ID必须从间隔0..2**96-1中统一随机选择,应该是加密随机的。重新发送相同的请求会重用相同的事务ID,但是客户端必须为新事务选择一个新的事务ID,除非新请求在比特上与先前的请求相同,并且从相同的传输地址发送到相同的IP地址。成功和错误响应必须相同事务ID作为他们相应的请求。当代理在同一端口上充当STUN服务器和STUN客户端时,代理发送的请求中的事务ID与代理接收的请求中的事务ID没有关系。
消息长度:  必须包含不包括20字节STUN报头的消息大小(以字节为单位)。由于所有STUN attribute都被填充为4字节的倍数,因此该字段的最后2位始终为零。这提供了另一种区分STUN包和其他协议包的方法。

头部的STUN固定部分之后是0个或多个属性。每个属性都是TLV (类型-长度-值)编码的。编码和属性本身的细节在第15节中给出。

4、STUN基本协议流程

本节定义了STUN协议的基本流程。它描述了消息是如何形成的,它们是如何发送的,以及它们在被接收时是如何处理的。它还定义了Binding方法的详细处理。本文档的其他部分描述了在某些情况下用户可能选择使用的可选程序。其他文档可以通过添加新方法、新属性或新错误响应代码来定义STUN的其他扩展。

4.1、生成请求或指示

当制定请求或指示消息时,代理在创建报头时必须遵循前面的规则。此外,消息class必须是“请求(Request)”或“指示(Indication)(视情况而定),并且该方法必须是Binding或在另一个文档中定义的某种方法(例如:Allocate方法)。

代理然后添加由方法或用法指定的任何属性。例如,一些用法可以指定代理使用认证方法(第10节)或FINGERPRINT属性(第8节)。

如果代理正在发送请求,它应该向请求添加SOFTWARE属性。代理可以在指示中包括SOFTWARE属性,这取决于方法。STUN的扩展应该讨论软件在新的指示中是否有用。

对于没有身份验证的Binding方法,不需要任何属性,除非用法另有说明。

如果已知,所有通过UDP发送的STUN消息都应该小于路径MTU。如果路径MTU未知,消息应该小于576字节,IPv4 [RFC1122]的第一跳MTU和IPv6 [RFC2460]的1280字节。该值对应于IP数据包的总大小。因此,对于IPv4,实际的STUN消息需要少于548字节(576减去20字节IP报头,减去8字节UDP报头,假设没有使用IP选项)。STUN不能处理请求在MTU下的情况,但是响应会大于MTU。这种限制对于STUN来说不是一个问题。对于STUN本身被用来探测STUN特性的情况,STUN限制是应该的,而不是必须的。在此应用程序或类似应用程序之外,必须遵循MTU约束。

4.2、发送请求或指示

代理然后发送请求或指示。本文档指定如何通过UDP, TCP, 或TLS-over-TCP发送STUN消息;将来可能会添加其他传输协议。STUN用法必须指定使用哪种传输协议,以及代理如何确定接收方的IP地址和端口。第9节描述了一种基于DNS的方法,用于确定用户可能选择使用的服务器的IP地址和端口。STUN可以用于任播地址,但只能用于UDP和不使用身份验证的用途。

在任何时候,一个客户端可能有多个与同一个STUN服务器未完成的STUN请求(即,多个正在进行的事务,具有不同的事务id)。如果没有对新事务速率的其他限制(例如ICE为连通性检查指定的限制或STUN在TCP上运行的限制),客户端应该通过RTO将新事务空间分配给服务器,并且应该将其自身限制为同一服务器上的十个未完成事务。

4.3、接收STUN消息

本节指定STUN消息的处理。此处指定的处理是针对本规范中定义的STUN消息;第12节定义了向后兼容性的附加规则。这些额外的过程是可选的,用法可以选择使用它们。首先,应用一组独立于class的处理操作。接下来是特定于class的处理,如以下小节所述。

当STUN代理收到STUN消息时,它首先检查该消息是否符合第6节的规则。它检查前两位是否为0,magic cookie字段是否具有正确的值,消息长度是否合理,以及方法值是否是受支持的方法。它检查特定方法是否允许的消息class。如果消息class是“成功响应”或“错误响应”,代理会检查事务id是否与仍在进行的事务匹配。如果正在使用FINGERPRINT扩展,代理会检查FINGERPRINT属性是否存在并包含正确的值。如果检测到任何错误,消息将被无声地丢弃。在STUN与另一协议复用的情况下,错误可能表明这不是真正的STUN消息;在这种情况下,代理应该尝试将消息解析为不同的协议。

然后,STUN代理进行使用指定的认证机制所需的任何检查(参见第10节)。

身份验证检查完成后,STUN代理会检查消息中未知的属性和已知但意外的属性。未知的理解-代理必须忽略可选属性。代理应该忽略已知但意外的属性。未知的需要理解的属性会导致依赖于消息class的处理,如下所述。

4.3.1、处理请求(request)

如果请求包含一个或多个未知的需要理解的属性,服务器将以错误代码为420(未知属性)的错误响应进行回复,并在列出未知的需要理解的属性的响应中包含UNKNOWN-ATTRIBUTES属性。

然后,服务器会执行该方法或特定用途所需的任何附加检查。如果所有检查都成功了,服务器将按照下面的描述制定一个成功响应

4.3.1.1、生成成功或错误的响应

当生成响应(成功或错误)时,服务器遵循第6节的规则。响应的方法与请求的方法相同,消息class是"Success Response" 或"Error Response"

 

对于错误响应,服务器必须添加包含上述处理中指定的错误代码的ERROR-CODE属性。原因短语不是固定的,但是应该适合错误代码。对于某些错误,消息中会添加其他属性。这些属性在指定错误代码的描述中有详细说明。例如,对于420(未知属性)的错误代码,服务器必须包括UNKNOWN-ATTRIBUTES属性。某些身份验证错误也会导致属性被添加(参见第10节)。扩展可以定义其他错误和/或在错误情况下要添加的附加属性。

如果服务器使用认证机制认证请求,那么服务器应该向响应添加适当的认证属性(参见第10节)。

服务器还添加特定方法或用法所需的任何属性。此外,服务器应该向消息中添加SOFTWARE属性。

 

对于Binding方法,不需要额外的检查,除非用法另有说明。当生成成功响应时,服务器将XOR-MAPPED-ADDRESS属性添加到响应中,其中属性的内容是请求消息的源传输地址。对于UDP,这是请求消息的源IP地址和源UDP端口。对于TCP和TLS-over-TCP,这是服务器看到的TCP的源IP地址和源端口。

4.3.1.2、发送成功或错误的响应

响应(成功或错误)通过接收请求的同一transport发送。如果请求是通过UDP接收的,则响应的目的IP地址和端口是接收到的请求消息的源IP地址和端口,并且响应的源IP地址和端口等于接收到的请求消息的目的IP地址和端口。如果请求是通过TCP 或TLS-over-TCP接收的,响应将在接收请求的同一TCP连接上发回。

4.3.2、处理指示(Indication)

如果指示包含未知的需要理解的属性,则该指示被丢弃,处理停止。

然后,代理会根据方法或特定用途的要求进行任何额外的检查。如果所有检查都成功,代理随后处理该指示。对于指示没有产生响应

对于Binding方法,不需要额外的检查或处理,除非用法另有说明。仅仅代理收到消息就刷新了中间NATs中的“绑定”。

由于指示不通过UDP重新传输(不同于请求),因此不需要在发送代理处处理指示的重新传输。

4.3.3、处理成功的响应

如果成功响应包含未知的需要理解的属性,则该响应被丢弃,事务被视为失败。

然后,客户端会执行该方法或特定用途所需的任何附加检查。如果所有检查都成功了,那么客户端将处理成功响应。

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

4.3.4、处理错误的响应

如果错误响应包含未知的需要理解的属性,或者如果错误响应不包含ERROR-CODE属性,那么事务就被简单地认为失败了

客户端然后执行认证机制指定的任何处理(参见第10节)。这可能会导致新的事务尝试。

此时的处理取决于错误代码、方法和用法;以下是默认规则:

  1. 如果错误代码是300到399,客户端应该认为事务失败,除非使用备用服务器扩展。参见第11节。
  2. 如果错误代码是400到499,客户端声明事务失败;在420(未知属性)的情况下,响应应该包含一个UNKNOWN-ATTRIBUTES属性,该属性提供附加信息。
  3. 如果错误代码是500到599,客户端可以重新发送请求;这样做的客户必须限制他们这样做的次数。

任何其他错误代码都会导致客户端认为事务失败。

4.4、FINGERPRINT机制

本节描述了STUN的可选机制,当STUN消息和其他协议的数据包在同一传输地址上多路复用时,该机制有助于区分STUN消息和其他协议的数据包。这个机制是可选的,STUN用法必须描述它是否被使用以及何时被使用。FINGERPRINT机制与RFC 3489不向后兼容,不能在需要这种兼容性的环境中使用。

在某些应用中,STUN消息与其他协议(如实时传输协议(RTP))在相同的传输地址上复用。为了应用第7节中描述的处理,STUN消息必须首先与应用包分开。

第6节描述了STUN报头中可用于此目的的三个固定字段。然而,在某些情况下,这三个固定字段可能不够

使用FINGERPRINT扩展时,代理将FINGERPRINT属性包含在它发送给另一个代理的消息中。第15.5节描述了该属性的位置和值。当代理接收到它认为是STUN消息时,除了其他基本检查之外,代理还检查消息是否包含FINGERPRINT属性,以及该属性是否包含正确的值。第7.3节描述了在STUN消息的整个处理过程中,何时执行FINGERPRINT检查。此附加检查有助于代理检测其他协议的消息,否则这些消息看起来可能是令人震惊的消息。

4.5、认证和消息完整性机制

短期凭证机制:

短期凭证机制假设,在STUN事务之前,客户端和服务器已经使用一些其他协议来交换用户名和密码形式的凭证。该证书有时间限制。时间限制是由用途决定的。

例如,在ICE使用[mmsic-ice]中,两个endpoints使用带外信令来商定用户名和密码,并且该用户名和密码在媒体会话期间适用。

此凭据用于在每个请求和许多响应中形成消息完整性(message-integrity)检查。没有像长期机制那样的挑战和回应;因此,由于证件的时间限制性质,重放被阻止。

a、生成请求或指示

对于请求或指示消息,代理必须在消息中包含USERNAME和MESSAGE-INTEGRITY属性。MESSAGE-INTEGRITY属性的HMAC按照第15.4节中的描述进行计算。请注意,密码从未包含在请求或指示中

b、接收请求或指示

在代理完成消息的基本处理后,代理按照指定的顺序执行下面列出的检查:

  1. 如果消息不同时包含MESSAGE-INTEGRITY和USERNAME属性:
  • 如果消息是请求,服务器必须拒绝请求并给出错误响应。此响应必须使用错误代码400(Bad Request)。
  • 如果消息是指示,代理必须无声地丢弃该指示。
  1. 如果USERNAME不包含服务器中当前有效的用户名值:
  • 如果消息是请求,服务器必须拒绝请求并给出错误响应。此响应必须使用错误代码401(Unauthorized)。
  • 如果消息是指示,代理必须无声地丢弃该指示。
  1. 使用与用户名相关联的密码,计算message integrity的值,如第15.4节所述。如果结果值MESSAGE-INTEGRITY属性的内容不匹配:
  • 如果消息是请求,服务器必须拒绝请求并给出错误响应。此响应必须使用错误代码401(Unauthorized)。
  • 如果消息是指示,代理必须无声地丢弃该指示。

如果这些检查通过,代理继续处理请求或指示。服务器生成的任何响应都必须包含MESSAGE-INTEGRITY,该属性是使用用于验证请求的密码计算的。响应不得包含USERNAME属性。

如果任何检查失败,服务器不得在错误响应中包含MESSAGE-INTEGRITY 或 USERNAME属性。这是因为,在这些故障情况下,服务器无法确定计算消息完整性所需的共享秘密。

c、接收响应

客户端在响应中寻找MESSAGE-INTEGRITY属性。如果存在,客户端使用用于请求的相同密码计算第15.4节中定义的响应上的message integrity。如果结果值与MESSAGE-INTEGRITY属性的内容匹配,则响应被视为已验证。如果值不匹配,或者如果MESSAGE-INTEGRITY不存在,则必须丢弃响应,就好像从未收到过响应一样。这意味着,如果适用,将继续重传。

 

长期凭证机制:

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

因为这些用户名和密码预计会在较长时间内有效,所以以摘要challenge的形式提供了阻止重放机制。在这种机制中,客户端最初发送请求,而不提供任何凭据或完整性检查。如下:

服务器拒绝该请求,为用户提供一个realm (用于指导用户或代理选择用户名和密码)和随机数。随机数提供重放保护。它是一个cookie,由服务器选择,并以指示有效期或客户端身份的方式进行编码。如下:

客户端重试该请求,这次包括其用户名和realm,并回显服务器提供的随机数。客户端还包括一个message-integrity,它提供了整个请求的HMAC,包括随机数。

服务器验证随机数并检查message-integrity。如果它们匹配,请求将被验证。如果随机数不再有效,它被认为是“过时的”,服务器拒绝请求,提供一个新的随机数。

在对同一服务器的后续请求中,客户端会重用以前使用的随机数、用户名、realm和密码。这样,在随机数被服务器无效之前,后续请求不会被拒绝,在这种情况下,拒绝向客户端提供新的随机数。

注意,长期凭证机制不能用于保护指示,因为指示不能被质疑。使用指示的用法必须使用短期凭证,或者省略它们的身份验证和message integrity。

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

a、生成请求

生成请求时有两种情况。在第一种情况下,这是客户端向服务器发出的第一个请求(由其IP地址和端口标识)。在第二种情况下,一旦先前的请求/响应事务成功完成,客户端就提交后续请求.

  1. 第一个请求:

如果客户端没有成功完成与服务器的请求/响应事务,它应该省略USERNAME、MESSAGE-INTEGRITY、REALM和NONCE属性。换句话说,发送第一个请求就好像没有应用身份验证或消息完整性一样。

      2.  后续请求

一旦请求/响应事务成功完成,服务器将向客户端呈现一个realm和随机数,并选择用户名和密码进行身份验证。客户端应该缓存用户名、密码、realm和随机数,以便随后与服务器通信。当客户端发送后续请求时,它应该包含USERNAME, REALM, 和 NONCE属性以及这些缓存的值。它应该包括一个MESSAGE-INTEGRITY属性,如第15.4节所述,使用缓存的密码进行计算。

b、接收请求

服务器完成请求的基本处理后,会按照指定的顺序执行下面列出的检查:

  1. 如果消息不包含MESSAGE-INTEGRITY属性,服务器必须生成错误代码为401(Unauthorized)的错误响应。此响应必须包含REALM值。建议REALM值是STUN服务器提供者的域名。响应必须包含由服务器选择的NONCE。响应不应包含USERNAME或MESSAGE-INTEGRITY属性。

  1. 如果消息包含MESSAGE-INTEGRITY属性,但缺少USERNAME, REALM, 或 NONCE属性,服务器必须生成错误代码为400的错误响应(Bad Request)。此响应不应包括USERNAME, NONCE,  REALM, 或MESSAGE-INTEGRITY属性。
  2. 如果NONCE不再有效,服务器必须生成错误代码为438(Stale Nonce)的错误响应。此响应必须包括NONCE和REALM属性,不应包括USERNAME 或MESSAGE-INTEGRITY属性。服务器可以使随机数无效,以提供额外的安全性。有关指南,请参见[RFC2617]第4.3节。
  3. 如果USERNAME属性中的用户名无效,服务器必须生成错误响应,错误代码为401(Unauthorized)。此响应必须包含REALM。建议REALM值是STUN服务器提供者的域名。响应必须包含由服务器选择的NONCE。响应不应包含USERNAME 或MESSAGE-INTEGRITY属性。 
  4. 使用USERNAME属性中与用户名相关联的密码,计算消息message integrity的值,如第15.4节所述。如果结果值与MESSAGE-INTEGRITY属性的内容不匹配,服务器必须拒绝请求并给出错误响应。此响应必须使用错误代码401(Unauthorized)。它必须包含REALM和NONCE属性,并且不应该包含USERNAME 或 MESSAGE-INTEGRITY属性。

如果这些检查通过,服务器将继续处理该请求。服务器生成的任何响应(上述情况除外)都必须包括MESSAGE-INTEGRITY属性,该属性是使用用来验证请求的用户名和密码计算的。不应包括REALM, NONCE, 和 USERNAME属性。

c、接收响应

如果响应是错误代码为401(Unauthorized)的错误响应,客户端应使用新事务重试该请求。该请求必须包含USERNAME,该用户名由客户端根据错误响应确定为该领域的适当用户名。请求必须包含从错误响应中复制的REALM。请求必须包含从错误响应中复制的NONCE。请求必须包含MESSAGE-INTEGRITY属性,使用用户名属性中与用户名相关联的密码计算。如果客户端没有从以前的尝试中更改USERNAME或REALM或其关联的密码,则不得执行此重试。

如果响应是错误代码为438(Stale Nonce)的错误响应,客户端必须使用438(Stale Nonce)响应中提供的新NONCE重试请求。此重试还必须包括USERNAME, REALM, 和 MESSAGE-INTEGRITY。

客户端在响应中寻找MESSAGE-INTEGRITY属性(成功或失败)。如果存在,客户端使用用于请求的相同密码,计算第15.4节中定义的响应上的message integrity。如果结果值与MESSAGE-INTEGRITY属性的内容匹配,则响应被视为已验证。如果值不匹配,或者如果MESSAGE-INTEGRITY不存在,则必须丢弃响应,就好像从未收到过响应一样。这意味着,如果适用,将继续重传。

5、STUN属性

STUN头之后是零个或多个属性。每个属性必须经过TLV编码,具有16位类型、16位长度和值。每个STUN属性必须以32位边界结束。如上所述,属性中的所有字段首先传输最高有效位。

长度字段中的值必须包含填充之前属性的值部分的长度(上图中的Nonce的长度),以字节为单位。因为STUN在32位边界上对齐属性,所以内容不是4字节倍数的属性用1、2或3字节的填充来填充,以便其值包含4字节的倍数。填充位被忽略,可以是任何值。

任何属性类型都可能在STUN消息中出现多次。除非另有说明,否则出现的顺序是重要的:只有第一次出现需要由接收者处理,任何重复都可能被接收者忽略。

为了允许本规范的未来修订在需要时添加新的属性,属性空间分为两个范围。类型值介于0x0000和0x7fff之间的属性是理解必需的属性,这意味着STUN代理无法成功处理消息,除非它理解该属性。类型值介于0x8000和0xffff之间的属性是可理解的可选属性,这意味着STUN代理如果不理解这些属性,可以忽略它们。

5.1、MAPPED-ADDRESS

MAPPED-ADDRESS属性指示客户端的反射传输地址。它由一个8位地址系列和一个16位端口组成,后跟一个代表IP地址的固定长度值。如果地址系列是IPv4,地址必须是32位。如果地址系列是IPv6,地址必须是128位。所有字段必须按网络字节顺序排列。

MAPPED-ADDRES属性的格式是:

address family可以采用以下值:

   0x01:IPv4

   0x02:IPv6

MAPPED-ADDRESS的前8位必须设置为0,并且必须被接收器忽略。这些位用于对齐自然32位边界上的参数。

5.2、XOR-MAPPED-ADDRESS

XOR-MAPPED-ADDRESS属性与MAPPED-ADDRESS属性相同,除了通过XOR函数混淆反射传输地址。

XOR-MAPPED-ADDRESS的格式是:

Family代表IP地址族,其编码与MAPPED-ADDRESS中的Family相同。

X-Port的计算方法是按主机字节顺序获取映射端口,将其与magic cookie中最高有效的16位进行异或运算,然后将结果转换为网络字节顺序。如果IP地址家族是IPv4,X-Address的计算方法是按主机字节顺序获取映射的IP地址,将其与magic cookie进行异或运算,并将结果转换为网络字节顺序。如果IP地址家族是IPv6,X-Address的计算方法是按照主机字节顺序获取映射的IP地址,将其与magic cookie和96位事务id的连接进行异或运算,并将结果转换为网络字节顺序。

注意: XOR-MAPPED-ADDRESS和 MAPPED-ADDRESS的区别仅在于它们对传输地址的编码。前者通过独占或用magic cookie对传输地址进行编码。后者直接用二进制编码。RFC 3489最初仅指定MAPPED-ADDRESS。然而,部署经验发现,一些NAT重写了包含NAT公共IP地址(如STUN的MAPPED-ADDRESS属性)的32位二进制有效载荷,这是一种善意但错误的尝试,旨在提供通用ALG功能。这种行为干扰了STUN的操作,也导致stun的消息完整性检查失败。

5.3、USERNAME

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

USERNAME的值是可变长度的值。它必须包含少于513字节的utf-8[RFC3629]编码序列,并且必须使用SASLprep [RFC4013]进行过处理。

5.4、MESSAGE-INTEGRITY

MESSAGE-INTEGRITY属性包含STUN消息的HMAC-SHA1 [RFC2104]。MESSAGE-INTEGRITY属性可以出现在任何STUN消息类型中。由于它使用SHA1哈希,HMAC将是20字节。用作HMAC输入的文本是STUN消息,包括报头,直到并包括MESSAGE-INTEGRITY属性之前的属性。除了出现在MESSAGE-INTEGRITY之后的FINGERPRINT属性之外,代理必须忽略MESSAGE-INTEGRIT之后的所有其他属性。

HMAC的关键取决于使用的是长期凭据还是短期凭据。对于长期凭据,密钥为16字节:

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

5.5、FINGERPRINT

FINGERPRINT属性可以出现在所有STUN消息中。属性的值被计算为STUN消息的CRC-32,直到(但不包括) FINGERPRINT属性本身,与32位值0x5354554e进行异或运算(异或运算在应用包中也使用crc-32的情况下有所帮助)。32位CRC是在ITU V.42 [ITU.V42.2002]中定义的,它具有x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1的生成器多项式。当FINGERPRINT属性存在时,它必须是消息中的最后一个属性,因此将出现在MESSAGE-INTEGRITY之后。

FINGERPRINT属性有助于区分STUN数据包和其他协议的数据包。参见第8节。

与MESSAGE-INTEGRITY一样,FINGERPRINT属性中使用的CRC覆盖了STUN消息头的长度字段。因此,在计算CRC之前,该值必须是正确的,并且包括CRC属性作为消息长度的一部分。当在消息中使用FINGERPRINT属性时,该属性首先被放置在具有虚拟值的消息中,然后计算CRC,然后更新属性值。如果MESSAGE-INTEGRITY属性也存在,那么在计算CRC之前,它必须具有正确的MESSAGE-INTEGRITY值,因为CRC也是在MESSAGE-INTEGRITY属性的值上完成的。

5.6、ERROR-CODE

ERROR-CODE属性用于错误响应消息。它包含一个300到699范围内的数字错误代码值,加上一个以UTF-8 [RFC3629],编码的文本原因短语,其代码分配和语义与SIP [RFC3261]和HTTP [RFC2616]一致。原因短语用于用户消费,可以是任何适合错误代码的词语。已定义错误代码的推荐原因短语包含在IANA错误代码注册表中。原因短语必须是少于128个字符(可长达763字节)的UTF-8 [RFC3629]编码序列。

为了便于处理,错误代码的class(数百位)与代码的其余部分分开编码,如图7所示。

 

保留位:  应为0,用于32位边界上的对齐。接收器必须忽略这些位。

Class:   代表数百位数的错误码。该值必须介于3和6之间。该数字表示模100的错误代码,其值必须介于0和99之间。

 

定义了以下错误代码及其推荐的原因短语:

              300尝试备用:客户端应该为此请求联系备用服务器。只有当请求包含USERNAME属性

                  和有效的MESSAGE-INTEGRITY属性时,才能发送此错误响应;否则,不得发送它,并建议使用错误代码400(Bad                       Request))。必须使用MESSAGE-INTEGRITY属性保护此错误响应,并且接收者必须在重定向到备用服务器之前验证                     此 响应的消息完整性。

              400错误请求:请求格式不正确。客户端不应在没有修改之前的尝试的情况下重试请求。

                      服务器可能无法为此错误生成有效的MESSAGE-INTEGRITY,因此客户端不能期望此响应具有有效的MESSAGE-                           INTEGRITY属性。

             401未授权:请求不包含继续操作的正确凭据。客户端应该使用正确的凭据重试请求。

            420未知属性:服务器收到一个STUN数据包,其中包含一个它不理解的理解必需属性。

                             服务器必须将该未知属性放入错误响应的UNKNOWN-ATTRIBUTE属性中。

             438过期随机数:客户端使用的随机数不再有效。客户端应该使用响应中提供的随机数重试。

             500服务器错误:服务器出现临时错误。客户端应该重试。

5.7、REALM

REALM属性可以出现在请求和响应中。它包含符合RFC 3261中描述的"realm-value"语法的文本,但没有双引号及其周围的空白。也就是说,它是非引用的realm-value (因此是qdtext或引用对的序列)。它必须是少于128个字符(可长达763字节)的UTF-8 [RFC3629]编码序列,并且必须已经使用SASLprep [RFC4013].进行了处理。

请求中REALM属性的存在表明长期凭据正在用于身份验证。某些错误响应中的存在表明服务器希望客户端使用长期凭据进行身份验证。

5.8、NONCE

NONCE属性可以出现在请求和响应中。它包含一系列qdtext或引号对,在RFC 3261中定义。请注意,这意味着NONCE属性将不包含实际的引号字符。参见RFC 2617,

它必须少于128个字符(可以长达763个字节)。

5.9、UNKNOWN-ATTRIBUTES

当ERROR-CODE属性中的响应代码为420时,UNKNOWN-ATTRIBUTES属性仅出现在错误响应中。

该属性包含一个16位值的列表,每个值代表服务器不理解的属性类型

5.10、SOFTWARE

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

5.11、ALTERNATE-SERVER

备用服务器代表标识STUN客户端应该尝试的不同STUN服务器的备用传输地址。

它以与MAPPED-ADDRESS相同的方式编码,因此通过IP地址引用单个服务器。IP地址系列必须与请求的源IP地址系列相同。

最后

以上就是奋斗裙子为你收集整理的STUN协议简要介绍的全部内容,希望文章能够帮你解决STUN协议简要介绍所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部