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