![RST 序列号和窗口大小](https://linux22.com/image/1487617/RST%20%E5%BA%8F%E5%88%97%E5%8F%B7%E5%92%8C%E7%AA%97%E5%8F%A3%E5%A4%A7%E5%B0%8F.png)
RFC793 对 RST 处理做出如下规定:
在除 SYN-SENT 之外的所有状态下,所有重置 (RST) 段都通过检查其 SEQ 字段进行验证。如果重置的序列号在窗口中,则重置有效。
但我不确定这句话到底是什么意思。假设我有以下场景:
因此套接字 2 告诉套接字 1 其窗口大小为 6 KB,然后套接字 1 将 6 KB 的数据发送到套接字 2。
然后套接字 1 向套接字 2 发送一个 RST 数据包:
那么,这种情况下会发生什么呢?RST 数据包会被套接字 2 接受吗?
答案1
Linux 仅在 RST 序列号是下一个预期序列号时才拆除 TCP 连接。应用此规则是为了避免盲目 TCP 重置攻击(请参阅RFC 5961 第 3.2 节)。因此适用以下规则:
如果设置了 RST 位并且序列号超出当前接收窗口,则静默丢弃该段。
如果设置了 RST 位并且序列号与下一个预期序列号 (RCV.NXT) 完全匹配,则 TCP 必须重置连接。
如果设置了 RST 位,并且序列号与下一个预期序列值不完全匹配,但在当前接收窗口内(RCV.NXT < SEG.SEQ < RCV.NXT+RCV.WND),则 TCP 必须发送确认(挑战 ACK):
<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
因此,如果您处于情况 1,您的 RST 段将被悄悄删除(至少在 Linux 上,这取决于实现,但应该得到尊重)。
答案2
一旦所有数据使用 MTU 值的片段机制从客户端传输到目的地,就会发起 FIN,而不是 RST。
- FIN:数据传输已完成,没有剩余的数据包。(优雅关闭)
- RST:我不在此端口上列出/我已超载。(强制关闭)
对于 RST 数据包,序列号是经过验证的,因为 src、dst 和中间设备应该终止会话和连接/状态表条目。