[2023][Protocol]TCP 建立连接

Note:本文为阅读RFC9293时的记录

Note:本文中 老旧的报文 或者其他类似的说法意为:因为网络拥塞或者其他原因导致延迟的报文。并且,该报文已经TCP新发送的新的同类型报文替代。比如:TCP对等体发送的SYN 命名为A报文,此时A报文因为网络拥塞原因发送了延迟,TCP对等体因为长时间没有收到对A报文的确认报文,所以发送了一个新的SYN报文,命名为B报文。此时A就是老旧报文(原文为:old duplicated),已经再无任何用处。

在阅读该篇文章之前,应该阅读TCP Sequence

三报文握手(3WHS) 是建立连接的基本步骤,这个过程通常有一个TCP peer 主动开启,由另一个 TCP peer 响应。也可以两个TCP Peer 同时主动开启,两个对等体同时发送 没有ACK置位的 SYN 报文。

即 SYN 置位的报文

为了 防止 旧的重复 SYN 报文 的到达使得接接收者误认为 对方也要主动开启连接,所以正确使用 “reset” 报文也是非常有必要的。

接下来展示最简单的3WHS过程。

在这里插入图片描述

其中 左箭头(–>) 代表报文是从 A 发往 B 的,并且被B正确收到,右箭头相反。

箭头可能为 (…) 代表报文延迟了

为了便于描述,这里省略了TCP报文的其他信息(如端口号等)

A 直接进入了 ESTABLISHED 状态

接下来看一个复杂一点的同步案例:

在这里插入图片描述

A,B 是同时开始主动连接的。

TCP实现必须支持 主动,被动,同时主动的打开方式。而且TCP必须跟踪 连接是主动还是被动打开从而达到 SYN-RECEIVED 状态的。

该案例下:AB 同时发送SYN,同时进入 SYN-RECEIVED 同时发送对对方SYN的确认,同时进入 ESTABLISHED 状态。

这里说 的 “同时” 简化了报文传输中时间上的差异

3WHS 是为了防止旧的(Old duplicated) SYN造成混乱。为此,指定了一个特殊的控制报文用于复位

如果对等体处于非同步状态(SYN-SEND 或者 SYN-RECEIVED 状态之一),则将在接收RESET报文后返回到 LISTEN 状态。

如果对等体已经处于同步状态(Establish,FIN-wait-1,FIN-wait-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WATI 之一),则RESET会终止连接并通知用户

,这种情况在 “Half-open” 中讨论。

案例:

在这里插入图片描述

  • 第二行 A 发送 ISN为100的SYN报文企图开启连接,但此时老旧的SYN(第二行)比新SYN先到达B。

  • 此时B发送对 旧SYN的确认,A收到后,发现我发的ISN是100,你怎么确认90的?

  • A 发送RESET 报文,重置B的状态,并重新发送SYN报文

之后的步骤就是简单的Open步骤。

如果 第6行的报文比RESET提前到达,则B也会发送RESET报文。

B认为,我预期的SEQ接下来应该从91开始,怎么来了个100的?

1.1 Half-Open Connection and Other Anomalies

如果说已经建立连接的两个TCP 对等体不知道对方因为某些原因关闭了,而自己仍然是Established状态,则此时这个连接称为半开连接。任何一方尝试发送报文,这个连接都会被重置。

half-open 并不常见 因为现代操作系统在关闭之前会通知进程关闭,如果软件设计有条理,则会在关闭时主动释放所有资源,包括TCP连接。

假如说有两个用户进行A,B 正在通信,此时A因为某种异常导致重启了,此时A再次启动时,A很有可能从头开始或从 保存点 开始重新发送数据。A 很可能会再次尝试打开连接,或者直接从连接上尝试发送数据 (A 认为连接已经打开了,因为是从保存点开始的,而且因为重启时间很短,A认为连接还没有被关闭);在后一种情况下,A会收到TCP实现的 连接未打开的异常。所以A不得不重新建立连接。

在这里插入图片描述

第二行就是典型的半开。

当SYN进行到第三行时,处于同步状态的B,收到了序列号为400的Segment,不在B的接收窗口范围内,所以B回复一个ACK报文用于声明自己接下来希望接收的序列号。

然后A发现这并不是对自己SYN的确认,此时A发现这是一个Half-Open连接,A发送了一个复位。B收到后,进入关闭状态,并重新开始监听,之后的步骤就是基本的3WHS。

上述是A在重启后主动发送SYN,如果A在重启后在主动开启之前,收到了B的同步状态的报文。

在这里插入图片描述

则在A收到该报文后,也是发现Half-Open,并立即发送RST。

如果双方都没有意图主动开启连接,但是其中一方收到未知的SYN报文,最终也会有RST报文

在这里插入图片描述

1.2 Reset Generation

TCP使用者可以在连接开启的任何时候发送Reset,只要发生了某些异常。

发送reset的一方之后应该进入TIME-WAIT状态,这通常有助于减少服务器的负载。

The TIME-WAIT state in TCP and its effect on busy servers | IEEE Conference Publication | IEEE Xplore

总的来说,如果连接的任何一方发现收到的报文显然不属于该连接,则就发送RST。如果不清楚是不是这种情况,则就不能发送RST。

总共有三种情况:

  • 如果连接已经处于关闭(CLOSE)状态,那么之后收到的任何报文,都必须回复RST;且状态必须一直保持在CLOSE。

ACK序列号处理方式: 如果收到的报文中,ACK置位,则RST必须使用该报文的ACK序列号+1 (如上图 TCP Peer A)。否则,RST的序列号为0,且ACK序列号为 收到报文Sequence Number字段与 Segment Length 之和。

  • 如果当前的状态处于未同步状态(LISTEN,SYN-SENT,SYN-RECEIVED),并且收到的报文 确认了一些仍未发送的内容,(即:这是一个不可接受的ACK报文),或者收到的报文不匹配 本地期望的信息(如MLS,Compartment等);此时就需要发送reset。

    ACK序列号与序列号处理方式如上

  • 如果连接已经处于同步状态 (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT),收到任何不可接受的Segment必须回复空(不携带任何数据)的ACK报文,以声明自己期望接收哪些数据。
    ACK序列号与序列号处理方式如上。

    不可接受的Segment:窗口规定的序列号范围之外,不可接受的ACK序列号

MLS : RFC 9293:TCP IPsec
第 6 章 使用多级别安全(MLS) Red Hat Enterprise Linux 8 | Red Hat Customer Portal

1.3 Reset Processing

在除了 SYN-SENT 之外所有TCP状态中,都需要检查收到RST报文的SEQ片段。如果SEQ在接收窗口声明的范围内,则就是合法的。对于 SYN-SENT 状态,想要置位的话则必须回复 对SYN的确认,同时RST置位即可。

A   	--> <SEQ=100><SYN>    		    -->   B
A		<-- <SEQ=1921,ACK=100+1,RST>	<--   B

这也是为什么RST需要将SEQ设置为收到的ACK报文的ACK.SEQ+1,因为只要是报文,就必须在对方的可接受窗口规定的序列号范围内

如果RST接收者认为该RST是合法的,则会改变自身的状态。

  • 如果在 LISTEN 状态收到了RST,则忽略

  • 如果在 SYN-RECEIVED 装填收到了 RST,假设该 SYN-RECEIVED 是从 LISTEN过渡来的,则直接返回到LISTEN状态。

  • 其他情况下,收到合法RST则将关闭连接,然后进入CLOSE状态

TCP 实现标准 允许在RST报文中附加一些数据,这些数据用于描述该RST产生的原因。目前仍未定义该数据的规范格式。

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天晴丶SnowCrystal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值