6. STUN 消息结构 (STUN Message Structure)
STUN 消息使用面向网络的格式以二进制编码 (最高有效字节或 octet 在前, 也通常称为 big-endian). 传输顺序在 RFC 791 [RFC0791] 的 Appendix B 中有详细描述. 除非另有说明, 数值常量均为十进制 (base 10).
所有 STUN 消息都必须以 20-byte 头部开始, 后跟零个或多个 Attributes. STUN 头部包含 STUN message type, magic cookie, transaction ID, 以及 message length.
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: STUN Message Header 的格式
每个 STUN 消息的最高有效 2 bits 必须为零. 当 STUN 与其他协议复用在同一端口上时, 这可用于将 STUN packets 与其他协议区分开来.
message type 定义 STUN 消息的 message class (request, success response, failure response, 或 indication) 和 message method (主要功能). 虽然存在四种 message classes, 但 STUN 中只有两类事务: request/response transactions (由一个 request message 和一个 response message 组成) 与 indication transactions (由一个 indication message 组成). 响应类被拆分为 error 和 success responses, 以帮助快速处理 STUN 消息.
message type 字段进一步细分为如下结构:
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: STUN Message Type Field 的格式
这里将 message type 字段中的 bits 从最高有效位 (M11) 到最低有效位 (M0) 展示. M11 到 M0 表示 method 的 12-bit 编码. C1 和 C0 表示 class 的 2-bit 编码. class 为 0b00 表示 request, class 为 0b01 表示 indication, class 为 0b10 表示 success response, class 为 0b11 表示 error response. 本规范定义了一个单一方法, Binding. method 与 class 相互正交, 因此对于每个 method, 都可能存在该 method 的 request, success response, error response, 以及 indication. 定义新 methods 的扩展必须指明该 method 允许哪些 classes.
例如, Binding request 的 class=0b00 (request), method=0b000000000001 (Binding), 并在前 16 bits 中编码为 0x0001. Binding response 的 class=0b10 (success response), method=0b000000000001, 并在前 16 bits 中编码为 0x0101.
magic cookie 字段必须以网络字节序包含固定值 0x2112A442. 在 RFC 3489 [RFC3489] 中, 该字段是 transaction ID 的一部分; 将 magic cookie 放在这个位置, 可使服务器检测客户端是否理解本修订规范新增的某些属性. 此外, 当 STUN 与其他协议复用在同一端口上时, 它有助于将 STUN packets 与其他协议的数据包区分开来.
transaction ID 是一个 96-bit 标识符, 用于唯一标识 STUN transactions. 对于 request/response transactions, transaction ID 由 STUN client 为请求选择, 并由服务器在响应中回显. 对于 indications, transaction ID 由发送 indication 的 agent 选择. 它主要用于关联 requests 与 responses, 但也在帮助防止某些类型攻击方面发挥少量作用. 服务器还使用 transaction ID 作为 key, 以便在所有客户端之间唯一标识每个 transaction. 因此, transaction ID 必须从区间 0 .. 2**96-1 中均匀且随机地选择, 并且应该具备密码学随机性. 同一请求的重传复用相同的 transaction ID, 但客户端必须为新的 transactions 选择新的 transaction ID, 除非新的请求与前一个请求按 bit 完全相同, 且从同一传输地址发送到同一 IP 地址. success 和 error responses 必须携带与其对应请求相同的 transaction ID. 当某个 agent 在同一端口上同时充当 STUN server 和 STUN client 时, 该 agent 发送的 requests 中的 transaction ID 与其接收的 requests 中的 transaction ID 没有关系.
message length 必须包含消息的大小, 单位为 bytes, 且不包括 20-byte STUN 头部. 由于所有 STUN attributes 都会填充到 4 bytes 的倍数, 该字段的最后 2 bits 始终为零. 这提供了另一种将 STUN packets 与其他协议的数据包区分开来的方式.
STUN 固定头部之后是零个或多个 attributes. 每个 attribute 都采用 TLV (Type-Length-Value) 编码. 编码细节以及各 attributes 本身见 Section 15.