STUN协议详解

STUN协议详解   基于RFC3489标准的stun协议,无法穿越TCP类型NAT,只是适用于在现有NAT类型下的UDP穿越,另一种特殊情况NAT也无法进行穿越,就是对称型NAT,在很多企业中就很多属于对称型NAT,后面会讲到。STUN的发现过程是基于UDP的NAT处理的假设;随着新的NAT设备的部署,这些假设可能会被证明是无效的,当STUN被用来获取一个地址来与位于其在同一NAT后面的对等体通信时,它就不起作用了。当stun服务器的部署不在公共共享地址域范围内时,stun就不起作用。1.定义STUN客户端:产生

大家好,又见面了,我是你们的朋友全栈君。

    本文是基于RFC5389标准的stun协议。STUN的发现过程是基于UDP的NAT处理的假设;随着新的NAT设备的部署,这些假设可能会被证明是无效的,当STUN被用来获取一个地址来与位于其在同一NAT后面的对等体通信时,它就不起作用了。当stun服务器的部署不在公共共享地址域范围内时,stun就不起作用。如果文中有不正确的地方,希望指出,本人感激不尽
1. 术语定义
STUN代理:STUN代理是实现STUN协议的实体,该实体可以是客户端也可以是服务端
STUN客户端:产生stun请求和接收stun回应的实体,也可以发送是指示信息,术语STUN客户端和客户端是同义词
STUN服务端:接收stun请求和发送stun回复消息的实体,也可以发送是指示信息,术语STUN服务端和服务端是同义词
映射传输地址:客户端通过stun获取到NAT映射的公网传输地址,该地址标识该客户端被公网上的另一台主机(通常是STUN服务器)所识别
2. NAT类型
NAT类型有四种:
    完全型锥(Full-Cone):所有来自同一个内部ip地址和端口的stun请求都可以映射到同一个外部ip地址和端口,而且,任何一个处于nat外的主机都可以向处于nat内的主机映射的外部ip和端口发送数据包。
    限制型锥(Restricted-Cone):所有来自同一个内部ip地址和端口的stun请求都可以映射到同一个外部ip地址和端口,和完全性锥不同的是,只有当处于NAT内的主机之前向ip地址为X的主机发送了数据包,ip地址为X的主机才可以向内部主机发送数据包。
    端口限制型锥(Port Restricted-Cone):与限制锥形NAT很相似,只不过它包括端口号。也就是说,一台IP地址X和端口P的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个IP地址X和端口P发送过数据包
   对称型锥(Symmetric):所有从同一个内网IP和端口号发送到一个特定的目的IP和端口号的请求,都会被映射到同一个IP和端口号。如果同一台主机使用相同的源地址和端口号发送包,但是发往不同的目的地,NAT将会使用不同的映射。此外,只有收到数据的外网主机才可以反过来向内网主机发送包。

3. 操作概述
在这里插入图片描述
   如图1为典型的stun配置,stun客户端连接到私有网络NET1,通过NAT1连接到私有网络NET2,NET2通过NAT2连接公网,stun服务器部署在公网。
   stun是一个简单的客户端-服务端模型的协议,客户端发送请求至服务端,然后服务端返回响应。有两种类型的请求——一种是Binding Request,通过UDP传输;一种是Shared Secret Request,通过基于TCP的TLS传输。Shared Secret Request要求服务器返回一个临时的username和pazuissword,这个username和password用于后续的Binding Request和Binding Response,保证身份认证和消息完整。Binding Request用于确定nat分配的绑定,客户端通过udp发送Binding Request到服务器,服务器获取到发送源的ip地址和端口,并将其复制到Binding Response中发送回客户端。在Binding Request消息中有一些参数设置使得客户端可以要求服务器在其他地方,或者用不同的ip和端口发送Binding Response。有一些属性用于提供消息完整性和身份验证。
   这些方法就是使用stun来发现NAT的类型以及学习使用Binding。STUN客户端通常嵌入到一个应用程序中,该应用程序需要获得一个公共IP地址和端口,可以用来接收数据,如:应用想通过公共ip和端口获取RTP数据,当应用启动时,内置stun客户端发送一个Shared Secret Request到服务器来获取username和passeword,然后发送Binding Request。通过DNS SRV记录可以发现STUN服务器,一般假设客户端已配置了用于查找STUN服务器的域。通常,这将是应用程序正在使用的服务的提供者的域(这样的提供者被鼓励部署STUN服务器,以便允许其客户通过NAT使用其应用程序)。当然,客户端也可以通过其他方式确定STUN服务器的地址或域名。STUN服务器甚至可以嵌入到终端系统中。
   Binding Request用于发现NAT的存在,以及发现由NAT映射后的公网ip地址和端口。Binding Request通过UDP协议发送到服务器端,在stun客户端和服务器端之间,Binding Request可能会通过一层或多层NAT。最终的结果是,服务器接收到的请求消息的源IP地址和端口,是最靠近stun服务器的那一层NAT映射后的公网地址。服务器将映射后的IP地址和端口复制并填写到Binding Response消息中发送给客户端。
   当客户端接收到Binding Response后,将解析出来的IP地址和端口与本地IP地址和端口进行比较,如果不匹配,则表明stun客户端处于一层或多层NAT之后。此时只是表明stun客户端处于NAT之后,还无法判断NAT的类型,为了进一步决定NAT的类型,客户端会发送第二个Binding Request,这一次是往不同的ip地址发送,如果Binding Response中的IP地址和端口和第一次的Binding Response的IP地址和端口不一样,那么stun客户端处于对称型锥的NAT之后,为了判断是否是完全型锥的NAT,客户端可以发送一个Binding Request并要求服务端用一个不同的IP和端口发送Binding Response,换句话说,如果客户但使用IP为X端口为Y向IP为A端口为B的主机发送请求,stun服务器使用IP为C端口为D向客户端发送回应,如果客户端能收到回应则表明其处于完全型锥。客户端也可以要求服务器使用相同的IP地址但端口不同来发送回应,以此来判断是处于端口限制型锥还是限制型锥。
4.Stun消息结构
   所有的stun消息都是由固定stun头开始,紧接着是stun净荷,净荷是一系列的属性值,其设置值是基于不同的消息类型,后面详细介绍。stun头包含stun消息类型,class,事务ID和长度。stun消息类型指示了binding请求或指示请求的类型,后面详细介绍;class指示了消息是否是一个request或者是成功回应或者是错误回应或指示信息等,事务ID是用于管理请求和相应的,长度是stun净荷的长度,不包含stun头部。
   所有的stun消息包含20字节的头部,头部结构如下:
在这里插入图片描述

如上图中,stun头部的开始两位必须为0,作用是当stun协议和其他协议公用同一个端口时,与其他协议的数据进行区分,STUN Message Type定义了STUN消息的消息类(请求、成功响应、失败响应或指示)和消息方法(主要功能),虽然有四个消息类,但STUN中只有两种类型的事务:请求/响应事务(由请求消息和响应消息组成)和指示事务(由单个指示消息组成),响应类分为错误响应和成功响应,以帮助快速处理STUN消息,消息类型字段将进一步分解为以下内容结构:
在这里插入图片描述
   这里消息类型字段中的位显示为最高位(M11)到最低位(M0)。M11通过M0表示一种12位编码的方法。C0和C1表示两位class的编码,class=0x00表示请求,class=0x01表示指示,class=0x10表示成功回应,class=0x11表示错误回应。该规范定义了一个方法:Binding,该方法和class是正交的,因此对于每个方法,该方法都可能有一个请求、成功响应、错误响应和指示。例如,一个绑定请求具有class=0b00 (request)和method=0b000000000001 (Binding),并被编码为前16位0x0001。绑定响应具有class=0b10(成功响应)和method=0b000100000001,并被编码为前16位0x0101。
   Magic Cookie字段必须以网络字节顺序包含固定值0x2112A442,在RFC3489中,字段是属于事务ID的一部分,将Magic Cookie放置在此位置是希望服务器检测客户端是否理解该修订规范中添加的某些属性,此外,当STUN与其他协议在同一端口上复用时,还可以帮助区分STUN报文和其他协议的报文。
   事务ID(Transaction ID)是一个96位的标识,用于唯一识别stun事务,对于请求/回应事务,事务ID由客户端产生,服务端直接复制后在回应消息中带回客户端。对于指示事务,它由发送指示的代理选择。它主要用于将请求与响应关联起来,不过它在帮助防止某些类型的攻击方面也扮演了角色。服务器还使用事务ID作为键,在所有客户机之间唯一地标识每个事务,因此,事务ID必须是统一的,从间隔0 ——2的96幂-1,并且应该是密码随机的。重新发送相同的请求复用相同的事务ID,但是客户端必须为新的事务选择一个新的事务ID,除非新的请求与之前的请求相同,并且从相同的传输地址发送到相同的IP地址,成功和错误响应必须携带与其相应请求相同的事务ID,当代理同时作为STUN服务器和STUN客户端在同一端口时,代理发送的请求中的事务id和代理收到的请求中的事务id没有关系。
   Message length 是包含20字节的stun头消息长度,因为所有的STUN属性都被填充为4个字节的倍数,所以这个字段的最后2位总是0。这为区分STUN报文和其他协议的报文提供了另一种方法。stun消息头之后有0个或多个属性。
5 协议处理流程
5.1 构建stun请求事务或指示事务
    当确定请求或指示消息时,代理在创建stun报头时必须遵循第4节中的规则。此外,消息类必须是“Request”或“Indication”(根据需要),方法必须是Binding或其他文档中定义的某个方法。然后添加若干方法带有的属性。如果发送给的是请求事务消息时,应该报文中添加SOFTWARE属性,对于指示事务消息,根据消息的类型来决定是否添加SOFTWARE属性。对于没有身份验证的Binding方法,除非用法另有规定,否则不需要任何属性。发送stun消息必须遵循UDP或TCP报文大小规则。所有通过UDP发送的STUN消息应该小于MTU,如果已知。如果不知道路径的MTU值,则报文长度应小于IPv4 [RFC1122]的576字节,IPv6 [RFC2460]的1280字节。该值对应IP包的整体大小。因此,对于IPv4,实际的STUN消息将需要小于548字节(576减去20字节的IP头,减去8字节的UDP头,假设没有使用IP选项)。STUN不提供处理请求报文字节数小于MTU值但响应报文字节数大于MTU的情况的能力,这个限制不会成为STUN的一个问题,MTU限制是应该的,而不是必须的,以考虑到STUN本身被用来探测MTU特征的情况。在这个或类似的应用程序之外,必须遵循MTU约束。
5.2 发送stun请求事务或指示事务
5.2.1 UDP发送stun请求事务或指示事务
    在UDP上运行STUN时,STUN消息有可能被网络丢弃,为了避免这个问题,客户端需要重传机制来发送请求事务,但是stun指示事务不需要重传,因此stun指示事务是不可靠的。客户端应该以RTO(“重传超时”)为间隔重新发送STUN请求消息,每次重传后加倍。RTO的值是根据RTT来估计的,初始值应该大于或等于500ms。RTO的值应该在事务完成后由客户端缓存,并用作同一服务器下一个事务的RTO的起始值,该值在10分钟后丢弃,直到收到回应或者重传次数达到一定次数(一般设置7次)后重传才结束,如果最后一个请求发出去,并在RTO时间内还没有收到回应,客户端应该认为事务传输失败。例如,假设RTO为500 ms,请求将在0 ms、500 ms、1500 ms、3500 ms、7500 ms、15500 ms和31500 ms时发送。如果客户端在39500毫秒后还没有收到响应,客户端将认为事务超时。
5.2.2 TCP或基于TCP的TLS发送stun请求事务或指示事务
    对于TCP协议和TLS-over-TCP协议,客户端先和服务器端建立TCP连接。在STUN的一些用法中,STUN是作为TCP连接上的唯一协议发送的。在这种情况下,它可以在没有任何额外帧或多路分解的帮助下发送。STUN 通过 TCP和tls -over TCP的可靠性由TCP本身处理,STUN协议级别没有重传。但是,对于请求/响应事务,如果客户机在发送SYN建立连接后Ti秒内没有收到响应,则认为事务超时。Ti默认39.5秒,选择这个值是为了使缺省初始RTO的TCP和UDP超时相等。此外,如果客户端无法建立TCP连接,或TCP连接被重置或在接收到响应之前失败,则任何正在进行的请求/响应事务都被认为失败。客户端可以通过一个TCP(或TLS- over-TCP)连接发送多个事务,并且它可以在收到对前一个请求的响应之前发送另一个请求,客户端应该保持连接打开,如果出现以下任一情况,则关闭TCP连接:
    1.后续没有stun请求或指示通过该连接发送
    2. 该连接上没有任何其他资源发送
    3.如果在该端口上复用其他应用程序协议,已经使用完其他应用程序
   4.如果使用映射地址与对等端已经建立了通信连接。
5.3 接收stun消息
    当一个STUN代理收到一个STUN消息时,它首先检查该消息是否遵守第4节的规则。检查前两位是否为0,magic cookie字段是否是正确的值,消息长度是否合理,方法是否支持;检查是否允许特定方法使用消息class。如果消息class是“Success Response”或“Error Response”,则代理检查事务ID是否与仍在进行中的事务匹配。如果使用了FINGERPRINT扩展,则代理将检查FINGERPRINT属性是否存在并包含正确的值。如果检测到任何错误,该消息将被静默丢弃。如果STUN与另一个协议多路复用,错误可能表明这不是一个真正的STUN消息,在这种情况下,代理应该尝试将消息解析为其他协议。然后,STUN代理将执行当前使用情况所指定的身份验证机制所需的任何其他检查,完成身份验证检查后,STUN代理会检查消息中的未知属性和已知但意外的属性。未知的理解可选属性必须被代理忽略,已知但意外的属性应该被代理忽略,不可理解的必选项属性依赖于消息类的处理,后续会讲解。
5.3.1 处理请求
   如果请求包含一个或多个不可理解的必选项属性,服务器将响应一个错误响应,错误代码为420 (unknown Attribute),并在响应中包含一个unknown – attributes属性,该属性列出了未知的理解必选项属性。然后进行其他额外检查,如果所有检查都成功,服务器将生成成功响应。
   当运行在UDP上时,服务器接收到的请求可能是一个事务的第一个binding请求,也可能是一次重传的binding请求。服务器必须响应重传的binding请求,以便保留以下属性:如果客户端接收到对重传的响应,而不是发送的第一个binding请求的响应,那么客户端和服务器的整体状态与只接收到第一个binding请求响应的情况相同,或,第一个binding请求接收的响应与binding重传请求响应都收到,在这种情况下,客户机将使用第一个。满足这一要求的最简单方法是让服务器记住通过UDP接收到的所有事务id以及它们在最近40秒内的相应响应,但是,这就需要服务器保持状态,并不适合任何未经过身份验证的请求。另一种方法是重新处理请求并重新计算响应。后一种技术必须只适用于幂等的请求(当相同的请求可以安全地重复而不影响系统的整体状态时,请求被认为是幂等的),并且对相同的请求产生相同的成功响应,绑定方法被认为是幂等的,请注意,某些罕见的网络事件可能会导致反射传输地址值更改,从而在不同的成功响应中出现不同的映射地址,扩展的启动必须讨论请求重新传输对不存储事务状态的服务器的影响。
<构建成功或错误回应>
   当构建响应(成功或错误)时,服务器遵循第4节的规则。响应的方法与请求的方法相同,消息class是“Success response”或“Error response”。对于错误响应,服务器必须添加一个包含指定错误代码的 ERROR-CODE属性,原因短语不是固定的格式,但应该可以描述错误代码的的错误引起的原因。对于某些错误,可能还会添加其他的属性,这些属性将在指定错误代码的描述中拼出,例如,对于错误代码为420(Unknown Attribute),服务器必须包含一个UNKNOWN-ATTRIBUTES属性。某些身份验证错误也会导致添加属性。如果服务器使用身份验证机制对请求进行了身份验证,则服务器应向响应中添加适当的身份验证属性,服务器还会添加了特定方法或用法所需的任何属性。此外,服务器还应向消息中添加一个SOFTWARE属性。对于绑定方法,除非用法另有规定,否则不需要进行其他检查。在形成成功响应时,服务器会向响应中添加一个 XOR-MAPPED-ADDRESS属性,其中该属性的内容是映射后公网传输地址或局域网的本地地址,对于UDP,这是请求消息的源IP地址和源UDP端口,对于TCP和TLS-over-TCP,这是服务器所看到的TCP连接的源IP地址和源TCP端口。
<发送成功或错误回应>
   响应(成功或错误)通过与接收请求相同的传输发送。如果通过UDP接收请求,则响应的目标IP地址和端口是接收的请求消息的源IP地址和端口,响应的源IP地址和端口等于接收的请求消息的目标IP地址和端口。如果通过TCP或TLS-通过TCP接收请求,则响应将在与接收请求相同的TCP连接上发送。
6 Stun消息属性
   stun消息头之后有0个或多个属性,每个属性必须是TLV编码,由16位类型Type、16位长度Length和可变的值组成,任何属性类型都可以在STUN消息中出现多次。除非另有规定,外观顺序很重要:接收器只处理第一次出现的属性,任何重复都可能被接收器忽略,结构如下:在这里插入图片描述
为了允许此规范的未来修订根据需要添加新属性,属性空间分为两个范围,类型值在0x0000和0x7FFF之间的属性是理解所必需的属性;类型值在0x8000和0xFFFF之间的属性是理解-可选属性,这意味着如果STUN代理不理解这些属性,则可以忽略这些属性。MESSAGE-INTEGRITY属性必须是消息中的最后一个属性。一个已知的属性,但是不会出现在消息中的必须忽略,例如MAPPED-ADDRESS属性只出现在回应消息中,如果在请求消息中出现了,那么服务器直接忽略该属性。下表中列出了哪些属性应该出现在哪些消息中,哪些属性又是必选的,或是可选的。
在这里插入图片描述
其中M代表此属性必选项,O代表可选项,C代表条件选项,是基于消息的其他方便选择,N/A表示此属性不能出想在这个消息中。
如属性结构图中Type类型值有以下几个:
MAPPED-ADDRESS
    MAPPED-ADDRESS,在Binding Response中携带Binding Requet消息的源IP地址和端口,可能是局域网的本地IP和端口,可能是nat映射的公网IP和端口,结构如下:
在这里插入图片描述
如上图,映射地址属性表示客户端的映射传输地址。它由一个8位地址族和一个16位端口组成,然后是一个表示IP地址的固定长度值。如果地址族是IPv4,则该地址必须为32位。如果地址族是IPv6,则该地址必须为128位。所有字段都必须按网络字节的顺序排列。映射地址的前8位必须设置为0,并且必须被接收器忽略,用于在自然32位边界上的对齐参数,Family有以值:
0x01:IPv4
0x02:IPv6
   此属性仅用于服务器,以实现与RFC3489[RFC3489]客户端的向后兼容性
XOR-MAPPED-ADDRESS
   XOR-MAPPED-ADDRESS属性与映射地址属性相同,只是这个属性的传输地址通过异或(xor)算法计算后存储。Family表示IP地址族,其编码与MAPPED-ADDRESS属性中的Family相同。
   X-Port是通过将映射地址按照主机字节顺与stun头部中magic cookie字段的低16位进行XOR算法计算,然后再按网络字节序顺序存入。如果IP地址族为IPv4,则X-Address为映射后IP地址以主机字节顺序与stun头部中magic cookie进行XOR算法计算,然后再按网络字节序顺序存入;如果IP地址族为IPv6,则X-Address为映射后IP地址以主机字节顺序与stun头部中magic cookie和事务ID的96位进行XOR算法计算,然后再按网络字节序顺序存入。
在这里插入图片描述
注意:
   XOR-MAPPED-ADDRESS和MAPPED-ADDRESS仅在其对传输地址的编码上有所不同
RESPONSE-ADDRESS
   RESPONSE-ADDRESS,在Binding Requet中携带IP地址和端口,告诉服务端往这个IP和端口中发送回应,此属性是可选的,如果请求中没有携带,则用服务器向获取到的请求消息源IP和端口发送回应。结构类型和MAPPED-ADDRESS类似
CHANGE-REQUEST
   type=0x0003,客户端使用CHANGE-REQUEST属性来请求服务器在发送响应时使用不同的地址和/或端口,属性位32bit,属性中包含两个flag。此属性只出现在请求中,这个属性的作用是决定客户端是在限制型锥NAT还是在端口限制型锥NAT之后,也是可选项如下:
在这里插入图片描述
标志A:“change IP”标志,如果为true,则请求服务器使用不同的IP地址(端口不变)发送绑定响应
一个绑定请求被接收
标志B:“change port”标志,如果为true,则请求服务器使用不同的端口(IP不变)发送绑定响应
一个绑定请求被接收
CHANGED-ADDRESS
   在Binding Respone中携带IP地址和端口,如果在绑定请求的change – Request属性中设置了“change IP”和“change port”标志,则change – address属性指示发送响应的IP地址和端口。结构类型和MAPPED-ADDRESS类似
   type=0x0005,出现在Binding Response中,通知客户端CHANGE-REQUEST属性起作用了
SOURCE-ADDRESS
属性出现在Binding Respone中,表示服务端发送绑定响应的主机源IP地址和端口,结构类型和MAPPED-ADDRESS类似
USERNAME和PASSWORD
   USERNAME,type=0x0006,PASSWORD,在Shared Secret Response中,提供给客户端临时的username和password,作用用于消息完整性检测,USERNAME和PASSWORD经常在Shared Secret Response消息中出现,在Shared Secret Binding中可选。USERNAME和是可变长度的,但是必须满足4字节整数倍以保证字节边界对齐。
MESSAGE-INTEGRITY
   通过请求消息和回应消息完整性检测。MESSAGE-INTEGRITY消息包含了stun消息的 HMAC-SHA1,消可以存在于任何STUN消息类型中。因为使用 SHA1 hash,HMAC占用20字节。作为HMAC输入的文本是STUN消息,包括消息头,直到message – INTEGRITY属性之前的属性(除了在消息完整性之后出现的指纹属性外,代理必须忽略在消息完整性之后出现的所有其他属性),然后,该文本用零填充,从而成为64字节的倍数。MESSAGE-INTEGRITY属性必须是任何STUN消息中的最后一个属性。HMAC的密钥取决于正在使用长期还是短期凭据。对于长期凭据,密钥为16个字节,计算公式如下:
          key = MD5(username “:” realm “:” SASLprep(password))
  也就是说,16字节字钥通过连接以下5个字段的MD5哈希形成:(1)删除任何引号和后空的用户名,从username 属性中获取(在这种情况下,已应用了SASLprep)(2)冒号;(3)realm 删除引号和后空的领域;(4)冒号;(5) password,删除任何空格,使用SASLprep处理计算之后。例如,如果用户名为“user”,realm 为“realm ”,password为“pass”,那么16字节的HMAC密钥将是对字符串“user:realm pass”执行MD5哈希的结果,结果散希为0x8493fbc53ba582fb4c044c456bdc40eb.
对于短期凭证,密钥为16个字节,计算公式如下:
          key = SASLprep(password)(其中SASLprep()在RFC4013[RFC4013]中定义)
   基于上述规则,用于构建消息完整性hash包括STUN消息头的长度字段。在执行hash之前,必须将信息完整性属性插入到信息中(包含虚拟内容)。然后,长度必须设置为指向消息的长度,直到并包括消息完整性属性本身,但不包括消息完整性之后的任何属性。执行计算后,可以填写消息完整性属性的值,STUN头中的长度值可以设置整个消息的长度。类似地,在验证消息完整性时,在计算HMAC之前,应调整长度字段以指向消息完整性属性的末尾,当信息完整性等属性出现在指纹之后时,一定需要进行这种调整。
FINGERPRINT
   FINGERPRINT属性可能出现在所有STUN消息中,属性值计算方法为STUN消息开始直至(但不包括)FINGERPRINT属性本身,与32位值为0x5354554e进行XOR运送。FINGERPRINT属性可以帮助区分STUN数据包和其他协议的数据包。
   与MESSAGE-INTEGRITY属性一样,FINGERPRINT属性中使用的CRC覆盖了STUN消息头的长度字段,因此,此值必须正确,并在计算CRC之前将CRC属性作为消息长度的一部分,在消息中使用FINGERPRINT属性时,首先将该属性用伪值放到消息中,然后计算CRC,然后更新该属性的值。如果也存在MESSAGE-INTEGRITY属性,则在计算CRC之前必须具有正确的消息完整性值,因为CRC也是通过超过消息完整性属性的值完成的。
ERROR-CODE
   ERROR-CODE,在Binding Error Response和Shared Secret Error Response中的属性,表明stun请求的错误,它是一个范围在100到699之间的数值加上一个用UTF-8编码的文本原因短语,并且在其代码分配和语义上与SIP[10]和HTTP[15]一致,理由短语用于用户使用,可以是任何适合响应代码的内容。原因短语的长度必须是4的倍数(以字节为单位)。这可以
如有必要,可在文本末尾添加空格。定义响应代码的推荐原因短语如下所示:
在这里插入图片描述
Class表示响应代码的百位数,取值范围为1 ~ 6。Number表示响应码的模为100,其值必须在0到99之间,以下定义了响应代码及其推荐的原因短语(括号中):
400(bad request):请求格式不正确
401(Unauthorized):绑定请求中没有携带MESSAGE-INTEGRITY属性
420(Unknown Attribute):服务器不理解请求中的必选项属性
430(Stale Credentials):绑定请求确实包含一个MESSAGE-INTEGRITY属性,但是它使用了一个已经过期的共享秘密。客户端应该获得一个新的共享密钥,然后重试。
431(Integrity Check Failure):绑定请求包含一个MESSAGE-INTEGRITY属性,但是HMAC验证失败。这可能是潜在攻击或客户端实现错误的信号。
432(Missing Username):绑定请求包含一个MESSAGE-INTEGRITY属性,但不包含USERNAME属性。两者都必须在场进行完整性检查
433(Use TLS):共享秘密请求必须通过TLS发送,但没有通过TLS接收)
500(Server Error):服务器出现了暂时的错误。客户端应该再试一次。
600((Global Failure):服务器拒绝满足请求。客户端不应该重试。
REALM
   领域属性可能存在于请求和响应中,它包含符合RFC3261[RFC3261]中所描述的“领域值”语法的文本,但没有双引号及其周围的空格,也就是说,它是一个,没有引号的REALM值。它必须是一个UTF-8[RFC3629]编码序列,其长度少于128个字符(可长达763个字节),并且必须使用SASLPrep[RFC4013]进行处理。
   请求中存在REALM属性表示长期凭据正在用于身份验证,在某些错误响应中表示服务器希望客户端使用长期凭据进行身份验证。
SOFTWARE
   SOFTWARE属性包含发送消息的代理正在使用的软件的文本说明。被客户端和服务器使用。其值应包括制造商和版本号,该属性对协议的操作没有影响,仅用作诊断和调试的工具。SOFTWARE的值为可变长度。它必须是一个UTF-8[RFC3629]编码序列,可少于128个字符(长度可达763个字节)
UNKNOWN-ATTRIBUTES
    UNKNOWN-ATTRIBUTES,只出现在当错误码为420的Binding Error Response或Shared Secret Error Response中,它指示了请求中未知的必选项属性,该属性包含一个由16位值组成的列表,每个值表示服务器无法理解的属性类型,如果未知属性的数量为奇数,则列表中必须有一个属性重复,因此列表的总长度为4字节的倍数,结构如下:
在这里插入图片描述
REFLECTED-FROM
   ,当绑定请求中包含 RESPONSE-ADDRESS属性时只出现在Binding Response中,该属性包含来自请求的源的身份(根据IP地址)。它的目的是提供可追溯性,这样STUN服务器就不能用作拒绝服务攻击

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160525.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • pycharm2021.2激活方法破解方法[通俗易懂]

    pycharm2021.2激活方法破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • android 应用的证书签名跟系统签名

    android 应用的证书签名跟系统签名作为软件行业的从业者都知道,一款软件的开发过程中肯定会诞生两种版本,即debug版本和release版本,debug版本包含有调试信息,一般来说都要比release版本大,android应用当然也不例外1.证书签名并不是所有的apk文件都能成功安装到安卓设备上,android系统要求只有签名后的apk文件才可以安装,因此我们还要对生成的apk文件进行签名才行在androidstudio中直接运行项目生成的都是测试版debug安装文…

  • Editplus注册码(长期有效)

    Editplus注册码(长期有效)/**温馨提示:一定不要有空格哦!*/用户名Vovan注册码3AG46-JJ48E-CEACC-8E6EW-ECUAW

  • python字符串的比较

    python字符串的比较关于其中字符串类型id引用驻留机制见python中的字符串的驻留机制字符串的比较操作:运算符:>,>=,<,<=,==,!= 比较规则:首先比较两个字符串中的第–个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较比较原理:两字符进行比较时,比较的是其ordinalvalue(原始值),调用内置函数ord可以得到指定字符的ordinalv

  • goland软件官方软件激活破解方法

    goland软件官方软件激活破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • 编程路上必定要知道的数据库语言SPL

    编程路上必定要知道的数据库语言SPL要说清这个目标,先要理解数据库是做什么的。数据库这个软件,名字中有个“库”字,会让人觉得它主要是为了存储的。其实不然,数据库实现的重要功能有两条:计算、事务!也就是我们常说的OLAP和OLTP,数据库的存储都是为这两件事服务的,单纯的存储并不是数据库的目标。我们知道,SQL是目前数据库的主流语言。那么,用SQL做这两件事是不是很方便呢?事务类功能主要解决数据在写入和读出时要保持的一致性,实现这件事的难度并不小,但对于应用程序的接口却非常简单,用于操纵数据库读写的代码也很简单。如果假定目前关系数据库的逻辑存储

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号