TCP 协议概述
TCP 是面向连接、可靠的传输层协议:传输前三次握手建连,结束后四次挥手释放。
TCP 报文段关键字段
| 字段 | 位数 | 作用 |
|---|---|---|
| 序列号(Seq) | 32 | 本段数据第一个字节的序号 |
| 确认号(Ack) | 32 | 期望收到对方下一段的序号 |
| SYN | 1 | 同步标志,建立连接 |
| ACK | 1 | 确认标志,确认号有效 |
| FIN | 1 | 结束标志,发送方无数据 |
| RST | 1 | 复位标志,异常终止连接 |
三次握手(连接建立)
客户端 服务端
| |
| —— [SYN] Seq=x, Ack=0 ——→ | 第一次
| CLOSED → SYN-SENT | LISTEN → SYN-RCVD
| |
| ←—— [SYN+ACK] Seq=y, Ack=x+1 —— | 第二次
| SYN-SENT → ESTABLISHED |
| |
| —— [ACK] Seq=x+1, Ack=y+1 ——→ | 第三次
| | SYN-RCVD → ESTABLISHED
三次报文:① 客户端发 SYN=1、随机序列号 Seq=x → SYN-SENT;② 服务端分配缓冲区回 SYN=1, ACK=1, Seq=y, Ack=x+1 → SYN-RCVD;③ 客户端回 ACK=1, Seq=x+1, Ack=y+1,双方 ESTABLISHED。第三次握手可携带数据。
为什么不是两次? 两次只能验证客户端发送、服务端接收;第三次让服务端确认自身发送与客户端接收能力,并防过期 SYN 误建连接。
四次挥手(连接释放)
TCP 全双工,每个方向必须独立关闭:
客户端(主动关闭) 服务端(被动关闭)
ESTABLISHED ESTABLISHED
| |
| —— [FIN] Seq=u, Ack=v ——→ | 第一次
| → FIN-WAIT-1 | → CLOSE-WAIT
| |
| ←—— [ACK] Seq=v, Ack=u+1 —— | 第二次
| → FIN-WAIT-2 |
| |
| ←—— [FIN+ACK] Seq=w, Ack=u+1 —— | 第三次
| | → LAST-ACK
| |
| —— [ACK] Seq=u+1, Ack=w+1 ——→ | 第四次
| → TIME-WAIT (等 2MSL ≈ 60s) | → CLOSED
| → CLOSED |
四次报文:① 客户端发 FIN=1(“我没数据了”)→ FIN-WAIT-1;② 服务端确认 → CLOSE-WAIT,客户端 → FIN-WAIT-2;③ 服务端发完剩余数据发 FIN=1 → LAST-ACK;④ 客户端确认 → TIME-WAIT,等 2MSL 后关闭。
TIME-WAIT 为何等 2MSL? (1) 确保最后 ACK 被服务端收到;(2) 让旧连接报文消失、不干扰新连接。
状态变迁汇总
| 阶段 | 客户端状态 | 服务端状态 |
|---|---|---|
| 初始 | CLOSED | LISTEN |
| 握手完成 | ESTABLISHED | ESTABLISHED |
| 主动关闭 | FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT → CLOSED | - |
| 被动关闭 | - | CLOSE-WAIT → LAST-ACK → CLOSED |
标志位速查
| 阶段 | SYN | ACK | FIN |
|---|---|---|---|
| 握手-1 | 1 | 0 | 0 |
| 握手-2 | 1 | 1 | 0 |
| 握手-3 | 0 | 1 | 0 |
| 挥手-1 | 0 | 0 | 1 |
| 挥手-2 | 0 | 1 | 0 |
| 挥手-3 | 0 | 1 | 1 |
| 挥手-4 | 0 | 1 | 0 |
SYN Flood 攻击与 SYN Cookie 防御
攻击原理
SYN Flood 是典型 DoS:攻击者伪造大量不存在的 IP 发 SYN,服务端为每个 SYN 分配资源(TCB,传输控制块)、回 SYN+ACK 并进 SYN-RCVD 等 ACK;伪造 IP 的 ACK 永不到来,半连接队列占满,正常用户无法建连。
攻击者 服务端
| —— SYN (伪造IP-A) ——→ | 分配TCB → SYN-RCVD
| —— SYN (伪造IP-B) ——→ | 分配TCB → SYN-RCVD
| —— SYN (伪造IP-C) ——→ | 分配TCB → SYN-RCVD
| ... (大量) ... | 半连接队列满!
| |
正常用户 —— SYN ——→ | ❌ 丢弃,无法响应
SYN Cookie 防御
SYN Cookie 核心:收到 SYN 不分配资源,把连接信息编码进序列号还给客户端,仅当收到合法 ACK 才分配资源。
具体流程:
流程:收到 SYN 不分配 TCB → 计算 cookie = hash(源IP, 源端口, 目的IP, 目的端口, 时间戳, 密钥) → 作为初始序列号 Seq=y 在 SYN+ACK 返回 → 真实客户端回 ACK, Ack=y+1(伪造 IP 不会回)→ 服务端验证 Ack-1 是否等于该 hash → 通过才分配 TCB 建连。
SYN Cookie 是 Linux 内核默认防御:半连接队列超阈值时自动启用。