从何说起说起 tcp 的连接过程,想必 “3次握手4次挥手”是大家广为熟知的知识,那么关于更细节更底层的连接过程也许就很少人能讲清楚了。

所以本文会先简单回顾一下 tcp 的 3次握手过程,然后重点聊一下 tcp accept 的过程,涉及到 tcp 半连接队列、全连接队列等的内容。

回顾一下
3 次握手
要了解 3 次握手的过程,可能需要先熟悉一下 tcp 协议的格式:

image.png

tcp segment 的头部有两个 2字节的字段 source port 和 dest port,分别表示本机端口以及目标端口,在 tcp 传输层是没有 IP 的概念的,那是 IP 层 的概念,IP 层协议会在 IP 协议的头部加上 src ip 和 dest ip;
4 个字节的 seq,表示序列号,tcp 是可靠连接,不会乱序;
4 个字节的 ack,表示确认号,表示对接收到的上一个报文的确认,值为 seq + 1;
几个标志位:ACK,RST,SYN,FIN 这些是我们常用的,比较熟悉的。其中 ACK 简写为 “.”; RST 简写为 “R”; SYN 简写为 “S”; FIN 简写为 “F”;
注意: ack 和 ACK 是不一样的意思,一个是确认号,一个是标志位

了解了 tcp 协议的头部格式,那么再来讲一下 3 次握手的过程:
image.png

客户端对服务端发起建立连接的请求,发送一个 SYN 包(也就是 SYN 标志位设置为 1),同时随机生成一个 seq 值 x,然后客户端就处于 SYN_SENT 状态;
服务端收到客户端的连接请求,回复一个 SYN+ACK包(也就是设置 SYN 和 ACK 标志位为 1),同时随机生成一个 seq 值 y,然后确认号 ack = x + 1,也就是 client 的 seq +1,服务端进入 SYN_RECV 阶段;
客户端收到服务端的 SYN+ACK 包,会回复一个 ACK 包(也就是设置 ACK 标志位为 1),设置 seq = x + 1,ack 等于 服务端的 seq +1,也就是 ack = y+1,然后连接建立成功;

半连接队列

全连接队列存放的是已经完成 3次握手,等待应用层调用 accept() 处理这些连接;其实还有一个半连接队列,当服务端收到客户端的 SYN 包后,并且回复 SYN+ACK包后,服务端进入 SYN_RECV 状态,此时这种连接称为半连接,会被存放到半连接队列,当完成 3 次握手之后,tcp 会把这个连接从半连接队列中移到全连接队列,然后等待应用层处理。

那么怎么查看半连接队列的大小呢?没有直接的 linux command 来查询半连接队列的长度,但是根据上面的定义,服务端处于 SYN_RECV 状态的数量就表示半连接的数量。所以采用一定的方式增大半连接的数量,看服务端 SYN_RECV 的数量最大值有多少,那就是半连接队列的大小。

那问题就来了,如何增大半连接的数量呢?这里采用到的就是 SYN-FLOOD 攻击,通过发送大量的 SYN 包而不进行回应,造成服务端创建了大量的半连接,但是这些半连接不会被确认,最终把 tcp 半连接队列占满造成溢出,并影响正常的连接。

半连接队列溢出
采用的工具是: hping3,一款很强大的工具。

————————————————
版权声明:本文为CSDN博主「rebootcat」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013051748/article/details/109684609