Sequence Number 与 Acknowledgement Number
- 1 定义 & 在 TCP 包中的位置
- 1.1 Seq 与 Ack 的作用
- 2 计算 Seq / Ack
- 3 问题
- 3.1 Seq / Ack 溢出怎么办?
- 3.2 为什么要随机选择 ISN?
- 3.3 ISN 是真随机吗?
定义 & 在 TCP 包中的位置
Sequence Number 和 Acknowledge Number 通常被简称为 Seq 与 Ack,其中后者与 TCP 中的 ACK flag 可能偶尔混淆
在此特别强调
本文中使用 Seq 代替 Sequence Number,Ack 代替 Acknowledge Number
本文中(虽然很少,但是存在)使用 ACK(大写字母)代表设置了 ACK flag 的包
Seq 和 Ack 存在于所有的包里,是固有字段;而 ACK 是一种特殊的包,专用于表示「这个包 ACK 了另一个/多个包」
注:因为存在数据包乱序的可能,所以事实上除了第一个 SYN 包和某些极端情况下的 RST 包以外都设置了 ACK flag https://networkengineering.stackexchange.com/questions/79795/is-the-syn-packet-the-only-packet-that-have-the-ack-flag-not-set
对于第一个 SYN 包,Seq 值随机选择(这个值被称为 ISN),Ack 值为 0
对于第一个对端响应的 SYN-ACK 包,Seq 值随机选择(与第一个 SYN 选择的 Seq 无关),Ack 值为第一个 SYN 包的 Seq 值 + 1(在 TFO 的情况下,还需要加上传送的数据的大小)
Seq 与 Ack 的作用
Seq 用来解决网络包乱序问题
Ack 用来解决丢包的问题
计算 Seq / Ack
一般情况下:
有两种理解方式
Ack 的值 = 对端 Seq 的值 + 对端包中携带的数据长度
Ack 的值 = 期望从发送方接收到的下一个字节的 Seq
Ack 的目的是帮助发送方了解哪些数据已经被成功接收,与包的数量、控制包都无关,只有带有数据的包才会影响到 Ack 的值
注意存在一个特殊情况:对于 SYN 或 FIN 包,即使它们没有携带数据,也需要将值 + 1(如果是 TFO,则是在增加了它携带数据的大小基础上 + 1)
三次握手时
三次握手时,计算 Seq / Ack 时需要「将 SYN 包视为多 1 字节」
数据传输时
数据传输时,根据传输的包大小确定 Seq / Ack
四次挥手时
四次挥手时,计算 Seq / Ack 时需要「将 FIN 包视为多 1 字节」
问题
Seq / Ack 溢出怎么办?
策略:回绕
在TCP协议中,Seq 是一个 32 位的无符号整数(取值范围是从0到2^32-1),计算 Seq 时,如果溢出,那么就直接给出溢出后的值(相当于重新经过 0 了,即回绕)
因存在窗口机制,因此 TCP 对端可以正确识别到回绕的 Seq 不会产生错误
为什么要随机选择 ISN?
作用一
TCP 握手采用随机序列号(不完全随机,而是随着时间流逝而线性增长,到了 2^32 尽头再回滚),为的就是让攻击者更难以猜测 sequence number,因为伪造的 sequence number 不在合法范围内,而被接收方丢弃,增加安全性。
作用二
最大可能为了防止历史报文被接收:历史建立连接的包可能重传,如果都是从 0 开始那么后续的包延迟到达可能浪费资源。
ISN 是真随机吗?
不是!
根据 RFC793,ISN = M + F(localhost, localport, remotehost, remoteport)
M 是一个伪计时器,这个计时器每隔 4 微秒加 1
F 是一个 Hash 算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值,要保证 hash 算法不能被外部轻易推算得出
对于一个相同的四元组,要 4.77h 才会出现 ISN 回绕的情况