5. 关联初始化
5.1. 关联的正常建立
希望与另一个 SCTP 端点 Z 建立关联的 SCTP 端点 A 必须发送一个 INIT chunk. 如果 Z 接受该关联, 它必须以包含 INIT ACK chunk 的分组作为响应. 关联建立过程进一步说明如下.
5.1.1. 处理流参数
在 INIT 或 INIT ACK chunk 中, 发送方可以在可选/可变长度参数部分包含 "Supported Address Types" 参数, 请求接收方使用特定地址类型. 如果发送方不支持所有地址类型, 或希望限制对端使用某些地址类型, 发送方应该包含此参数.
INIT 或 INIT ACK 的接收方必须使用列表中指定的一种地址类型, 或使用发送该 INIT 或 INIT ACK 所用的地址类型 (如果该类型未列出), 来发送后续所有通信.
如果接收方不支持或希望避免发送方期望的任何地址类型, 它可以中止该关联, 并且应该发送 "Unsupported Address Type" 错误.
注: 如果 INIT 或 INIT ACK 包含 "Supported Address Types" 参数, 即使接收方能够使用其他地址类型, 它也必须只使用该参数中列出的地址类型之一, 或该 INIT/INIT ACK 发送到的地址类型.
在 INIT 或 INIT ACK chunk 中, 发送方通过其中包含的 "Number of Outbound Streams (OS)" 和 "Number of Inbound Streams (MIS)" 参数表明自己的流容量.
接收方应该将发送方在 INIT 或 INIT ACK 的 OS 字段中指示的值用作自身入站流的最大数量 (即接收方的 MIS). 发送方使用 MIS 参数限制对端可用于发送用户消息的流数量.
在 INIT 或 INIT ACK 中, 发送方的 Number of Outbound Streams (OS) 和 Number of Inbound Streams (MIS) 不得为 0.
如果接收方收到 OS 或 MIS 值为 0 的 INIT 或 INIT ACK, 接收方应该中止该关联, 发送 ABORT chunk, 并且可以报告 "Invalid Mandatory Parameter" 错误.
接收方必须还将其出站流使用数量限制为 INIT 或 INIT ACK 的 MIS 字段中收到的实际数量. 换言之, 关联建立后, 端点将使用如下数量:
Number of outbound streams to send user messages =
minimum(local OS, peer's MIS)
Number of inbound streams to receive user messages =
minimum(local MIS, peer's OS)
5.1.2. 处理地址参数
在初始化期间 (发送 INIT 或 INIT ACK 之前), 发送方应该使用可选 IPv4 Address 参数和/或 IPv6 Address 参数, 在 INIT 或 INIT ACK 中包含自己的全部地址. 省略此可选参数表示该端点只有一个地址, 即用于发送 INIT 或 INIT ACK 的源地址.
在发送 INIT chunk 之前, 端点应该始终进入 COOKIE-WAIT 状态.
注: INIT chunk 中没有地址并不表示发送端点不接受其他地址. 相反, 没有地址表示发送方不希望对端主动监听这些地址, 但它会接受从其对端任一地址发送来的消息.
如果接收方不支持发送方在 INIT 或 INIT ACK 中提供的任何地址类型, 它应该中止该关联, 并且可以发送 "Unsupported Address Type" 错误原因.
INIT 或 INIT ACK 的接收方必须记录提供的所有地址信息 (无论其来源如何, 包括来自 IP 头部,IPv4 Address 参数和/或 IPv6 Address 参数的信息), 并使用这些信息确定自己的传输地址集合.
如果发送方包含 "Host Name Address" 参数, 接收方必须立即发送 ABORT chunk, 并且可以包含 "Unresolvable Address" 错误原因.
注: "Host Name Address" 参数的使用已废弃. 接收方必须忽略 INIT 或 INIT ACK 中的任何 "Host Name Address" 参数, 并且应该以 ABORT chunk 响应.
5.1.3. 生成 State Cookie
发送 INIT ACK 的端点应创建 State Cookie, 并将其放入 INIT ACK 的 State Cookie 参数中. State Cookie 的使用见 Section 5.1.3.
State Cookie 应至少包含以下必要信息:
- 从收到的 INIT chunk 中取得的信息 (包括 Initiate Tag 和可选/可变长度参数)
- State Cookie 创建时间
- Lifespan (cookie 有效的时间)
- 一种用于认证 State Cookie 完整性和真实性的方法 (例如 Message Authentication Code (MAC))
实现注: State Cookie 可用于保存正在建立的关联的其他状态信息. 这允许端点在关联建立期间推迟资源 (TCB) 分配. 这种优化称为 "Cookie Approach", 可防御简单的拒绝服务攻击.
发送 INIT ACK 的实现应该使 State Cookie 足够难以被攻击者猜中. 推荐做法是在 State Cookie 中包含:
- 随机 nonce (每个关联实例唯一)
- 时间戳
- 对端源地址
- 对端源端口
- 本地目的地址
- 本地目的端口
- 覆盖上述全部字段的 MAC
创建此 MAC 所需的密钥应该在 SCTP 栈初始化时创建, 并应周期性刷新. 该密钥必须对通信双方之外的任何人保密.
在 INIT ACK 的 State Cookie 参数中包含这些值, 可用于验证 COOKIE ECHO chunk 中返回的 State Cookie. 验证过程见 Section 5.1.4.
此外, 发送方可以包含任何其他数据, 用于生成 State Cookie, 以验证 COOKIE ECHO 中返回的 cookie 并建立关联.
注: MAC 计算必须包含时间戳, 以确保重放的 cookie 不能作为拒绝服务攻击工具使用.
5.1.4. State Cookie 处理
当端点在 COOKIE ECHO chunk 中收到 State Cookie 时, 它必须按以下方式验证该 cookie:
-
验证 State Cookie 的 MAC 有效. 如果 MAC 无效, 静默丢弃该分组.
-
验证 State Cookie 未过期. 如果 State Cookie 已过期, 端点应该发送一个 Cause Code 设置为 "Stale Cookie Error" 的 ERROR chunk, 并静默丢弃该分组. State Cookie 的过期程度可使用 "Cookie Preservative" 参数调整. 见 Section 5.1.3.
-
检查源地址和端口号是否与 State Cookie 中保存的值匹配. 如果不匹配, 静默丢弃该分组.
如果 State Cookie 有效, 端点应该创建到该对端的关联, 并向发送方发送 COOKIE ACK chunk. 随后端点应将该关联转入 ESTABLISHED 状态.
5.1.5. State Cookie 认证
实现必须使用如下技术或等价技术保护 State Cookie 的完整性和真实性.
推荐技术是在 State Cookie 中包含 Message Authentication Code (MAC). MAC 应该使用发送方已知但任何潜在攻击者未知的密钥计算.
MAC 算法应该至少与 [RFC2104] 和 [RFC3174] 中定义的 HMAC-SHA-1 一样安全.
创建和验证 MAC 需要密钥. 该密钥应该周期性变更 (例如每隔数小时), 以限制攻击者通过观察合法流量推断密钥的能力.
在密钥变更期间, 实现应该保留旧密钥一段时间 (至少为 cookie 生命周期的两倍), 以允许验证使用旧密钥创建的 cookie.
5.1.6. 正常关联建立示例
在最简单的情况下, 端点 A 请求与端点 Z 启动关联的正常关联建立过程如下:
Endpoint A Endpoint Z
INIT ----[INIT ACK with State Cookie]----->
<----------[COOKIE ECHO]-------------
----------[COOKIE ACK]--------------->
此时, 两端的关联均为 ESTABLISHED.
详细步骤:
A) 端点 A 向端点 Z 发送 INIT chunk, 表明其希望建立关联. 在 INIT chunk 中, 端点 A 必须提供其 Verification Tag (供来自 Z 的所有分组使用),其支持的初始 TSN,出站流数量 (OS),入站流最大数量 (MIS), 以及其他传输地址 (如有).
B) 收到 INIT 后, 端点 Z 应该以 INIT ACK chunk 响应. 在 INIT ACK 中, Z 必须提供其 Verification Tag,初始 TSN,OS,MIS 和传输地址 (如适用). 此外, Z 必须创建 State Cookie 并将其包含在 INIT ACK 中.
C) 收到包含 State Cookie 的 INIT ACK 后, 端点 A 应该以 COOKIE ECHO chunk 响应. COOKIE ECHO chunk 必须包含在 INIT ACK 中收到的 State Cookie. 此外, 端点 A 可以在同一分组中捆绑用户数据与 COOKIE ECHO 一起发送.
D) 收到 COOKIE ECHO 后, 端点 Z 将验证 State Cookie. 如果有效, Z 将创建关联并以 COOKIE ACK chunk 响应. 此外, Z 可以在同一分组中捆绑用户数据与 COOKIE ACK 一起发送.
E) 收到 COOKIE ACK 后, 端点 A 会将其关联状态从 COOKIE-ECHOED 变为 ESTABLISHED. A 现在可以在已建立的关联上发送和接收用户数据.
5.2. 处理重复或非预期的 INIT,INIT ACK,COOKIE ECHO 和 COOKIE ACK
在关联生命周期的任意时刻, 端点都可能收到非预期或重复的 INIT,INIT ACK,COOKIE ECHO 或 COOKIE ACK chunk. 本节说明如何处理这些 chunk.
5.2.1. CLOSED 状态下收到 INIT
如果端点处于 CLOSED 状态并收到 INIT chunk, 它应该按 Section 5.1 中的说明以 INIT ACK 响应.
5.2.2. Cookie-Wait 或 Cookie-Echoed 状态下的非预期 INIT
如果端点处于 COOKIE-WAIT 或 COOKIE-ECHOED 状态, 且收到的 INIT chunk 的 Initiate Tag 与其记录的对端 Verification Tag 不匹配, 端点应该丢弃旧 TCB (如有), 并以 INIT ACK 响应该新的 INIT chunk.
如果端点处于 COOKIE-WAIT 或 COOKIE-ECHOED 状态, 且收到的 INIT chunk 的 Initiate Tag 与其记录的对端 Verification Tag 匹配, 端点应该以 INIT ACK 响应, 但不改变其状态. 当对端未收到或丢失 INIT ACK 时, 可能出现这种情况.
5.2.3. CLOSED 或 COOKIE-WAIT 状态下的非预期 INIT ACK
如果端点处于 CLOSED 状态或 COOKIE-WAIT 状态并收到 INIT ACK, 端点应该发送 ABORT chunk, 并且可以包含 "Out of the Blue" 错误原因 (见 Section 3.3.10).
如果端点处于 COOKIE-WAIT 状态, 且收到的 INIT ACK 的 Initiate Tag 字段与自己的 Tag 不匹配, 端点应该进入 CLOSED 状态, 销毁 TCB, 并发送 ABORT chunk.
5.2.4. 存在 TCB 时处理 COOKIE ECHO
本节说明端点在 CLOSED 和 COOKIE-ECHOED 以外状态收到 COOKIE ECHO chunk 时的行为.
实现注: 端点可能在关联生命周期的任何时候收到 COOKIE ECHO chunk, 通常是由于对端重传或网络延迟.
如果端点收到 COOKIE ECHO chunk, 且同一关联已有 TCB, 端点应该按以下操作之一处理:
A) 如果当前状态为 ESTABLISHED, 端点应该静默丢弃 COOKIE ECHO. 或者, 如果对端在 COOKIE ECHO 中包含了不正确的 verification tag, 端点可以发送 ABORT chunk.
B) 如果当前状态为 SHUTDOWN-ACK-SENT, 端点应该静默丢弃 COOKIE ECHO.
在所有其他情况下, 端点应该按 Section 5.2.4 的规则将 COOKIE ECHO 视为建立新关联的尝试, 但可使用现有 TCB 中的任何信息来优化关联建立过程.
5.2.5. 处理重复 COOKIE ACK
如果端点在 COOKIE-ECHOED 状态之外收到 COOKIE ACK chunk, 它应该静默丢弃该 chunk.
5.2.6. 处理 Stale COOKIE 错误
如果端点发送 COOKIE ECHO chunk 后处于 COOKIE-ECHOED 状态, 并收到包含 "Stale Cookie" 错误原因的 ERROR chunk, 端点可以尝试使用新的 INIT chunk 重新建立关联.
如果端点选择重试, 它应该在新的 INIT chunk 中包含 "Cookie Preservative" 参数, 其值设置为收到的 "Stale Cookie" 错误中指定的 Measure of Staleness 字段.
如果端点选择不重试, 它应该进入 CLOSED 状态, 并向其上层报告该问题.
5.3. 其他初始化问题
5.3.1. 默认端口的选择
SCTP 端点应该支持接收和发送到 UDP 端口 9899 的 SCTP 分组 (SCTP over UDP 封装的默认端口).
5.3.2. IPv4/IPv6 共存
实现应该按 [RFC4213] 的建议支持同时使用 IPv4 和 IPv6 地址.
5.3.3. SCTP 关联标识符
每个 SCTP 关联由一对 Verification Tag 唯一标识:
- 本地 Verification Tag (由对端在其 INIT 或 INIT ACK 中提供)
- 对端 Verification Tag (在本地 INIT 或 INIT ACK 中发送)
这对 Tag 用于对收到的 SCTP 分组进行解复用.
5.4. 路径验证
在正常运行期间, SCTP 端点必须使用 heartbeat 机制验证其对端路径的可达性.
在初始化期间 (发送 INIT ACK 后), 端点应该使用 heartbeat 机制验证 INIT 或 INIT ACK 中收到的所有地址均可达.
此验证应该在关联进入 ESTABLISHED 状态后立即开始.
实现注: 如果端点收到包含多个 IP 地址的 INIT 或 INIT ACK, 它应该通过向每个地址发送 HEARTBEAT 来尝试验证所有提供的地址.
在验证过程中未响应 HEARTBEAT 的地址应该标记为非活动, 且不应在正常数据传输中使用, 除非之后证明其为活动状态 (通过 HEARTBEAT 或数据传输).
本章仍有后续内容...
有关第 5 章的更多详细内容 (包括特定错误处理,超时机制和安全相关考虑), 请参阅 RFC 4960 完整文本.