6. STUN Message Structure (STUN消息结构)
STUN消息使用面向网络的格式以二进制编码 (最高有效字节或八位组在前,通常也称为大端序 (big-endian))。传输顺序在 RFC 791 [RFC0791] 的附录B中有详细描述。除非另有说明,数字常量采用十进制 (基数10)。
所有STUN消息必须 (MUST) 以20字节头部开始,后跟零个或多个属性 (Attributes)。STUN头部包含STUN消息类型、魔术饼干 (magic cookie)、事务ID (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) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
图2: STUN消息头部格式 (Format of STUN Message Header)
每个STUN消息的最高有效2位必须 (MUST) 为零。当STUN与其他协议在同一端口上多路复用时,这可以用来区分STUN数据包与其他协议。
消息类型 (message type) 定义了消息类别 (request, success response, failure response, 或 indication) 和STUN消息的消息方法 (message method) (主要功能)。虽然有四种消息类别,但STUN中只有两种类型的事务: 请求/响应事务 (request/response transactions) (由请求消息和响应消息组成) 和指示事务 (indication transactions) (由单个指示消息组成)。响应类别分为错误响应和成功响应,以帮助快速处理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|
+--+--+-+-+-+-+-+-+-+-+-+-+-+-+
图3: STUN消息类型字段格式 (Format of STUN Message Type Field)
这里消息类型字段中的位显示为最高有效位 (M11) 到最低有效位 (M0)。M11到M0表示方法的12位编码。C1和C0表示类别的2位编码。类别 0b00 是请求 (request),类别 0b01 是指示 (indication),类别 0b10 是成功响应 (success response),类别 0b11 是错误响应 (error response)。本规范定义了单一方法: Binding。方法和类别是正交的,因此对于每种方法,该方法可能有请求、成功响应、错误响应和指示。定义新方法的扩展必须 (MUST) 指示该方法允许哪些类别。
例如,绑定请求 (Binding request) 具有类别=0b00 (request) 和方法=0b000000000001 (Binding),并编码到前16位为 0x0001。绑定响应 (Binding response) 具有类别=0b10 (success response) 和方法=0b000000000001,并编码到前16位为 0x0101。
注意: 这种不幸的编码是由于 [RFC3489] 中的值分配没有考虑使用位字段编码指示、成功和错误。
魔术饼干字段必须 (MUST) 包含以网络字节序表示的固定值 0x2112A442。在 RFC 3489 [RFC3489] 中,此字段是事务ID的一部分; 将魔术饼干放在此位置允许服务器检测客户端是否能理解在此修订规范中添加的某些属性。此外,它有助于在STUN与其他协议在同一端口上多路复用时区分STUN数据包与其他协议的数据包。
事务ID (transaction ID) 是一个96位标识符,用于唯一标识STUN事务。对于请求/响应事务,事务ID由STUN客户端为请求选择,并由服务器在响应中回显。对于指示,它由发送指示的代理选择。它主要用于将请求与响应关联起来,尽管它在帮助防止某些类型的攻击方面也起着小作用。服务器还使用事务ID作为密钥来跨所有客户端唯一标识每个事务。因此,事务ID必须 (MUST) 从区间 0 .. 2**96-1 中均匀且随机地选择,并且应该 (SHOULD) 是加密随机的。相同请求的重发重用相同的事务ID,但客户端必须 (MUST) 为新事务选择新的事务ID,除非新请求与先前请求按位相同并从相同的传输地址发送到相同的IP地址。成功响应和错误响应必须 (MUST) 携带与其对应请求相同的事务ID。当代理在同一端口上同时充当STUN服务器和STUN客户端时,代理发送的请求中的事务ID与代理接收的请求中的事务ID没有关系。
消息长度 (message length) 必须 (MUST) 包含消息的大小 (以字节为单位),不包括20字节的STUN头部。由于所有STUN属性都填充到4字节的倍数,因此此字段的最后2位始终为零。这提供了另一种方法来区分STUN数据包与其他协议的数据包。
在STUN固定头部之后是零个或多个属性。每个属性都采用TLV (Type-Length-Value) 编码。编码的详细信息以及属性本身在第15节中给出。