查看 SCTP 的关联初始化

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

介绍

在我 之前的帖子 中,我们探讨了 SCTP 数据包是如何编码的以及它们包含哪些协议元素。接下来我们将看看三个 SCTP 过程 - 关联创建、用户数据传输和关联拆除。每个过程都需要特定的消息流,这将在单独的帖子中进行审查。

RFC 4960 第 4 节 有一个 SCTP 关联的状态图。有两个主要状态 - 已关闭和已建立。它们之间的传输包含更多的中间状态(COOKIE-WAIT、COOKIE-ECHOED 等)。只有当关联处于 ESTABLISHED 状态时,两个端点才能交换用户数据。这是通过关联初始化过程完成的。一旦成功完成,对等方就可以按照用户数据传输程序交换数据。最后,连接随着关联过程的终止而关闭。现在我们将回顾协会创建过程。

关联初始化

关联初始化程序在 第 5 节 中描述。请求连接的对等方是客户端,接受它的是服务器,就像在 TCP 中一样。流程如图所示。 1. chunk 名称以粗体显示,下面是它们最重要的参数。请记住,在 第一篇文章 中,单个 SCTP 数据包可以包含多个块。

图 1:SCTP 关联初始化

初始化块

首先,客户端向服务器发送 INIT 块。你可以在图上看到一个示例。 2. 它具有以下参数(在 第 3.3.2 节 中描述):

  • Initiate tag:该值应由接收方保存,并设置在从服务器到客户端的每条消息的 SCTP 公共头中的验证标记字段中。请注意,包含 INIT 块的消息中的验证标记为 0,因为它是通信中的第一个。

  • Advertised Receiver Window Credit (a_rwnd):发送方的缓冲区大小。有关详细信息,请查看 第 3.3.2 节 中的描述。

  • 出站流数:客户端向服务端请求的流数。请注意,服务器可能不接受此号码。流计数的过程将在本文后面描述。该值不能为零。

  • 入站流数:客户端支持的最大入站流数。服务器有义务尊重这个值,否则会发生错误。该值也不能为零。

  • 初始 TSN:0 到 4294967295 之间的随机数。TSN 代表传输序列号。每个数据块(用户数据)都附加了一个唯一的 TSN,用于确认和重复块检测。此参数说明发送方(在本例中为客户端)将使用的第一个 TSN。对于每个新的数据块,TSN 都会递增 1。

  • 支持的地址类型和 IPv4 地址参数:它们包含可用于到达客户端的 IP 地址。由于 SCTP 的多宿主特性,它们可以不止一个。我为此计划了一个专门的帖子,所以我现在不讨论它。

  • ECN参数:该参数与关联建立没有任何关系,略过。它在 RFC 4960 附录 A 中进行了描述。

  • 转发 TSN 支持的参数:此参数来自 SCTP 部分可靠性扩展。查看 RFC 3758 第 3.2 节 以获取更多信息。

图 2: init.pcapng

初始化确认块

服务器通过发送带有 INIT ACK 块的消息来继续关联建立过程。在图。 3 您可以看到上一节中对 INIT 块的响应。您应该注意的第一件事是 SCTP 消息的公共标头中的 Verification 标记。它设置为 0x08fe2132 - 来自 INIT 块的 Initiate 标记。请记住,只有 INIT 消息的 Verification 标签设置为 0。每个后续消息都将 Verification 标签设置为接收方的 Initiate 标签。现在让我们继续处理 INIT ACK 块的参数。其中一些与 INIT 块中的相同,但含义略有不同:

  • Initiate tag:服务器宣布它的Verification tag。

  • Advertised Receiver Window Credit (a_rwnd):查看INIT中的描述。

  • 出站流数:从服务器到客户端的流数。该值应等于或小于 INIT 消息中的“入站流数”参数。如果该值较大,则客户端可以中止关联建立过程。

  • 入站流数:服务器支持的最大入站流数。如果客户端的 INIT 块中的'Number of outbound stream'参数大于该参数,则客户端必须调整其最大输出流数。

  • 初始 TSN:服务器将使用的第一个 TSN。查看 INIT 部分中的描述以获取更多详细信息。

  • ECN 参数和 Forward TSN 支持的参数:与 INIT 相同。

您已经注意到,此时客户端和服务器都知道对方支持的输入和输出流的数量。此过程用于为每个方向上的两个对等体协商可接受的数量。另请注意,协议协商的是最大值,而不是每个方向上的实际流数。这并不意味着 SCTP 用户有义务使用所有这些。

INIT ACK 块中还有一些参数,这些参数在 INIT 中不存在:

  • 状态cookie:当收到INIT消息时,服务器生成TCB(查看 Key terms ),代表Transmission Control Block。它包含服务器所需的关联的所有信息。状态 cookie 参数包含带有 MAC(消息验证代码)的 TCB。它用于 TCB 的完整性检查和认证。有关 MAC 的更多信息,请查看 RFC 2104 或维基百科文章 Hash-based message authentication code 。状态cookie生成后,服务器删除所有关联信息。目的是不让服务器容易受到类似 SYN flood 的 DoS 攻击 。简而言之——如果恶意用户试图用 INIT 消息淹没服务器,SCTP 堆栈将只计算状态 cookie 并发送 INIT ACK,而不会保留任何状态信息,这可能会耗尽其资源。如果您对 TCB 是如何生成的感到好奇,请查看 第 13 节 。状态 cookie 生成在 第 5.1.3 节 中介绍。

有关 INIT ACK 块的更多信息,请查看 第 3.3.3 节

图 3: init_ack.pcapng

COOKIE ECHO 块

当客户端收到带有状态 cookie 的 INIT ACK 块时,它应该立即响应 COOKIE ECHO。这个块非常简单,你可以在图 1 中看到一个例子。 4.它只有一个参数Cookie,里面包含了接收到的状态cookie。 COOKIE ECHO 块在 3.3.11 节 中描述。

图 4: cookie_echo.pcapng

Cookie 确认块

服务器接收 COOKIE ECHO 块并提取状态 cookie。然后它读取 TCB 并计算其 MAC。如果它与消息中的相匹配,则 TCB 被视为有效且已通过身份验证。然后服务器从中提取建立关联所需的关于关联的所有信息。成功时,服务器返回 COOKIE A​​CK 块,并认为关联已建立。这个块中没有任何参数,所以这里没有更多的解释。您可以在 第 5.1.5 节 中找到有关此过程的更多详细信息,并且在 第 3.3.12 节 中描述了 COOKIE A​​CK 块。您可以在图 5 中看到带有此块的示例消息。

图 5: cookie_ack.pcapng

协会现已初始化

通过此过程,SCTP 关联被认为已初始化,并且已准备好在两个方向上传输用户数据。这里的描述省略了一些我认为不相关的细节,例如各种超时、意外消息处理等。如果你想了解这些细节,我建议你自己阅读整个 第 5 节 。下次我们将继续进行用户数据传输。