Skip to main content

15. STUN Attributes (STUN属性)

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

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

图4: STUN 属性格式 (Format of STUN Attributes)

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

任何属性类型都可以 (MAY) 在 STUN 消息中出现多次。除非另有规定,否则出现顺序很重要: 接收器只需要处理第一次出现,接收器可以 (MAY) 忽略任何重复项。

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

STUN 属性类型集由 IANA 维护。本规范定义的初始集见第 18.2 节。

本节的其余部分描述了本规范中定义的各种属性的格式。

15.1. MAPPED-ADDRESS

MAPPED-ADDRESS 属性指示客户端的反射传输地址 (reflexive transport address)。它由 8 位地址族和 16 位端口组成,后跟表示 IP 地址的固定长度值。如果地址族是 IPv4,地址必须 (MUST) 是 32 位。如果地址族是 IPv6,地址必须 (MUST) 是 128 位。所有字段必须 (must) 采用网络字节序。

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

图5: MAPPED-ADDRESS 属性格式 (Format of MAPPED-ADDRESS Attribute)

地址族可以采用以下值:

  • 0x01: IPv4
  • 0x02: IPv6

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

此属性仅由服务器用于实现与 RFC 3489 [RFC3489] 客户端的向后兼容性。

15.2. XOR-MAPPED-ADDRESS

XOR-MAPPED-ADDRESS 属性与 MAPPED-ADDRESS 属性相同,只是反射传输地址通过 XOR 函数进行混淆。

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

图6: XOR-MAPPED-ADDRESS 属性格式 (Format of XOR-MAPPED-ADDRESS Attribute)

Family 表示 IP 地址族,编码方式与 MAPPED-ADDRESS 中的 Family 相同。

X-Port 通过将主机字节序的映射端口与魔术饼干的最高有效 16 位进行异或,然后将结果转换为网络字节序来计算。如果 IP 地址族是 IPv4,X-Address 通过将主机字节序的映射 IP 地址与魔术饼干进行异或,然后将结果转换为网络字节序来计算。如果 IP 地址族是 IPv6,X-Address 通过将主机字节序的映射 IP 地址与魔术饼干和 96 位事务 ID 的连接进行异或,然后将结果转换为网络字节序来计算。

编码和处理属性值的前 8 位的规则、处理属性多次出现的规则以及处理地址族的规则与 MAPPED-ADDRESS 相同。

注意: XOR-MAPPED-ADDRESS 和 MAPPED-ADDRESS 仅在其传输地址的编码方式上有所不同。前者通过将传输地址与魔术饼干进行异或来编码传输地址。后者直接以二进制形式编码它。RFC 3489 最初仅指定了 MAPPED-ADDRESS。然而,部署经验发现,一些 NAT 重写包含 NAT 公共 IP 地址的 32 位二进制有效载荷,例如 STUN 的 MAPPED-ADDRESS 属性,这是善意但误导的尝试提供通用 ALG 功能。这种行为干扰了 STUN 的操作,也导致 STUN 的消息完整性检查失败。

15.3. USERNAME

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

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

15.4. MESSAGE-INTEGRITY

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

HMAC 的密钥取决于是否使用长期或短期凭证。对于长期凭证,密钥是 16 字节:

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

也就是说,16 字节密钥是通过对连接以下五个字段的结果进行 MD5 哈希来形成的: (1) 用户名,删除任何引号和尾随空值,取自 USERNAME 属性 (在这种情况下已经应用了 SASLprep); (2) 单个冒号; (3) 领域,删除任何引号和尾随空值; (4) 单个冒号; 以及 (5) 密码,删除任何尾随空值并使用 SASLprep 处理后。例如,如果用户名是 'user',领域是 'realm',密码是 'pass',则 16 字节 HMAC 密钥将是对字符串 'user:realm:pass' 执行 MD5 哈希的结果,生成的哈希为 0x8493fbc53ba582fb4c044c456bdc40eb。

对于短期凭证:

key = SASLprep(password)

其中 MD5 在 RFC 1321 [RFC1321] 中定义,SASLprep() 在 RFC 4013 [RFC4013] 中定义。

与长期凭证一起使用时的密钥结构有利于在也使用 SIP 的系统中部署。通常,使用 SIP 的摘要认证机制的 SIP 系统实际上不会在数据库中存储密码。相反,它们存储一个称为 H(A1) 的值,该值等于上面定义的密钥。

基于上述规则,用于构造 MESSAGE-INTEGRITY 的哈希包括来自 STUN 消息头部的长度字段。在执行哈希之前,MESSAGE-INTEGRITY 属性必须 (MUST) 插入到消息中 (带有虚拟内容)。然后必须 (MUST) 将长度设置为指向消息的长度,直到并包括 MESSAGE-INTEGRITY 属性本身,但不包括之后的任何属性。一旦执行计算,就可以填写 MESSAGE-INTEGRITY 属性的值,并且可以将 STUN 头部中长度的值设置为其正确值——整个消息的长度。类似地,在验证 MESSAGE-INTEGRITY 时,应在计算 HMAC 之前将长度字段调整为指向 MESSAGE-INTEGRITY 属性的末尾。当诸如 FINGERPRINT 之类的属性出现在 MESSAGE-INTEGRITY 之后时,这种调整是必要的。

15.5. FINGERPRINT

FINGERPRINT 属性可以 (MAY) 出现在所有 STUN 消息中。属性的值计算为 STUN 消息直到 (但不包括) FINGERPRINT 属性本身的 CRC-32,与 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 属性必须 (MUST) 是消息中的最后一个属性,因此将出现在 MESSAGE-INTEGRITY 之后。

FINGERPRINT 属性可以帮助区分 STUN 数据包与其他协议的数据包。参见第8节。

与 MESSAGE-INTEGRITY 一样,FINGERPRINT 属性中使用的 CRC 覆盖来自 STUN 消息头部的长度字段。因此,在计算 CRC 之前,此值必须正确并将 CRC 属性作为消息长度的一部分包含在内。在消息中使用 FINGERPRINT 属性时,首先将属性放入具有虚拟值的消息中,然后计算 CRC,然后更新属性的值。如果 MESSAGE-INTEGRITY 属性也存在,则在计算 CRC 之前,它必须 (must) 具有正确的消息完整性值,因为 CRC 也覆盖 MESSAGE-INTEGRITY 属性的值。

15.6. ERROR-CODE

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

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

图7: ERROR-CODE 属性 (ERROR-CODE Attribute)

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

保留位应该 (SHOULD) 为 0,用于在 32 位边界上对齐。接收器必须 (MUST) 忽略这些位。Class 表示错误码的百位数。值必须 (MUST) 介于 3 和 6 之间。Number 表示错误码模 100,其值必须 (MUST) 介于 0 和 99 之间。

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

300 Try Alternate: 客户端应该联系备用服务器以获取此请求。仅当请求包含 USERNAME 属性和有效的 MESSAGE-INTEGRITY 属性时,才必须 (MUST) 发送此错误响应; 否则,禁止 (MUST NOT) 发送它,建议使用错误码 400 (Bad Request)。此错误响应必须 (MUST) 受 MESSAGE-INTEGRITY 属性保护,接收器必须 (MUST) 在将自己重定向到备用服务器之前验证此响应的 MESSAGE-INTEGRITY。

注意: 未能为 300 响应生成和验证消息完整性允许路径上的攻击者伪造 300 响应,从而导致后续 STUN 消息被发送到受害者。

400 Bad Request: 请求格式错误。客户端不应该 (SHOULD NOT) 在不修改先前尝试的情况下重试请求。服务器可能无法为此错误生成有效的 MESSAGE-INTEGRITY,因此客户端禁止 (MUST NOT) 期望此响应上有有效的 MESSAGE-INTEGRITY 属性。

401 Unauthorized: 请求不包含正确的凭证以继续。客户端应该使用适当的凭证重试请求。

420 Unknown Attribute: 服务器收到包含它不理解的必须理解属性的 STUN 数据包。服务器必须 (MUST) 将此未知属性放入其错误响应的 UNKNOWN-ATTRIBUTE 属性中。

438 Stale Nonce: 客户端使用的 NONCE 不再有效。客户端应该使用响应中提供的 NONCE 重试。

500 Server Error: 服务器遇到临时错误。客户端应该重试。

15.7. REALM

REALM 属性可以出现在请求和响应中。它包含满足 RFC 3261 [RFC3261] 中描述的 "realm-value" 语法但没有双引号及其周围空格的文本。也就是说,它是一个未加引号的 realm-value (因此是 qdtext 或 quoted-pair 的序列)。它必须 (MUST) 是少于 128 个字符的 UTF-8 [RFC3629] 编码序列 (最长可达 763 字节),并且必须 (MUST) 使用 SASLprep [RFC4013] 处理过。

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

15.8. NONCE

NONCE 属性可以出现在请求和响应中。它包含 qdtext 或 quoted-pair 的序列,这些在 RFC 3261 [RFC3261] 中定义。请注意,这意味着 NONCE 属性不会包含实际的引号字符。有关服务器中随机数值选择的指南,请参阅 RFC 2617 [RFC2617] 第 4.3 节。

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

15.9. UNKNOWN-ATTRIBUTES

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

该属性包含 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attribute 1 Type | Attribute 2 Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attribute 3 Type | Attribute 4 Type ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

图8: UNKNOWN-ATTRIBUTES 属性格式 (Format of UNKNOWN-ATTRIBUTES Attribute)

注意: 在 [RFC3489] 中,此字段通过复制最后一个属性填充到 32。在本规范的此版本中,改为使用属性的正常填充规则。

15.10. SOFTWARE

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

15.11. ALTERNATE-SERVER

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

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