FIN 数据包乱序并覆盖?
out of order FIN packet and overwrite?
在浏览开源代码库时,我想到了一个有趣的场景。
假设在成功建立 TCP 连接后,TCP 客户端必须发送一个序列号 = 101 的数据包。相反,它发送一个序列号为 201 的 FIN。现在 TCP 服务器认为 FIN 乱序并将其排队并等待一个数据包到达。
我的问题是,根据 RFC,如果服务器收到序列号 = 101 且长度 = 150 的数据包,TCP 端点的行为应该是什么。它是否会覆盖之前发送的 FIN?或者服务器修剪数据包直到 FIN 序列号?或者它依赖于 TCP 实现?
根据 RFC 793 中的一些段落
"3.如果连接处于同步状态(ESTABLISHED,
FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, 结束, LAST-ACK, TIME-WAIT),
任何不可接受的段(超出 window 序列号或
不可接受的确认号)必须只引出一个空的
包含当前 send-sequence 号码的确认段
以及指示下一个预期序列号的确认
将被接收,并且连接保持相同状态。"
.....
“考虑处理传入片段的一种自然方式是
想象一下,他们首先测试了正确的序列号(即,
它们的内容在预期的范围内 "receive window"
在序列号 space) 然后他们通常排队
并按序号顺序处理。
当一个片段与其他已经接收到的片段重叠时,我们会重建
段只包含新数据,并调整 header 字段
保持一致。
...
我的回复:
请记住,如果发生这种情况,那是因为客户端的 bad-behaving TCP。不是针对 out-of-order,而是针对带有 FIN 标志的段中的错误序列。或者可能是攻击。
当服务器端的TCP接收到带有SEQ=201的报文段时,它会将这个报文段存储一段有限的时间,并且会发回一个101的ACK,因为它正在等待那个SEQ号。
那么当SEQ=101的报文段到达时,接收端的TCP在接收到SEQ=101的报文段后会有一个新的receivewindow。从第一个到达的 SEQ=201 段开始,它应该只获取字节 251 之后的数据(在我的测试中,它没有这样做,而是从 SEQ=101 的段中删除了重叠的字节——这可能取决于实现),如果有的话,并接受 FIN。接收方 TCP 将发回一个 ACK。当服务器端关闭套接字时,接收方 TCP 将发回一个 [FIN, ACK] 段。
为了测试它,我有一个完全按照您描述的方式执行的客户端(这是用用户 space 中的原始套接字完成的,不可能用 TCP 套接字模拟它。服务器是一个简单的 nodejs 服务器),发送 FIN 段,15 秒后发送前一个段。服务器读取接收到的数据,并在 10 秒后关闭套接字。
这里是tcpdump,可以看到TCP服务器端响应:
[rodolk@localhost ~]$ sudo tcpdump -i p2p1 -vv tcp
tcpdump: listening on p2p1, link-type EN10MB (Ethernet), capture size 65535 bytes
19:33:03.648216 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [S], cksum 0x5f49 (correct), seq 523645, win 500, length 0
19:33:03.649826 IP (tos 0x0, ttl 128, id 26590, offset 0, flags [DF], proto TCP (6), length 44)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [S.], cksum 0x1ac8 (correct), seq 1576251572, ack 523646, win 8192, options [mss 1460], length 0
19:33:03.651208 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [.], cksum 0x5091 (correct), seq 1, ack 1, win 500, length 0
19:33:03.651567 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 74)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [F.], cksum 0x8121 (correct), seq 122:156, ack 1, win 500, length 34
19:33:03.651891 IP (tos 0x0, ttl 128, id 26591, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [.], cksum 0x5314 (correct), seq 1, ack 1, win 65392, length 0
19:33:18.652083 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 171)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [P.], cksum 0xf973 (correct), seq 1:132, ack 1, win 500, length 131
19:33:18.652834 IP (tos 0x0, ttl 128, id 26593, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [.], cksum 0x5313 (correct), seq 1, ack 157, win 65237, length 0
19:33:28.661041 IP (tos 0x0, ttl 128, id 26594, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [F.], cksum 0x5312 (correct), seq 1, ack 157, win 65237, length 0
19:33:28.961756 IP (tos 0x0, ttl 128, id 26595, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [F.], cksum 0x5312 (correct), seq 1, ack 157, win 65237, length 0
在浏览开源代码库时,我想到了一个有趣的场景。 假设在成功建立 TCP 连接后,TCP 客户端必须发送一个序列号 = 101 的数据包。相反,它发送一个序列号为 201 的 FIN。现在 TCP 服务器认为 FIN 乱序并将其排队并等待一个数据包到达。 我的问题是,根据 RFC,如果服务器收到序列号 = 101 且长度 = 150 的数据包,TCP 端点的行为应该是什么。它是否会覆盖之前发送的 FIN?或者服务器修剪数据包直到 FIN 序列号?或者它依赖于 TCP 实现?
根据 RFC 793 中的一些段落
"3.如果连接处于同步状态(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, 结束, LAST-ACK, TIME-WAIT), 任何不可接受的段(超出 window 序列号或 不可接受的确认号)必须只引出一个空的 包含当前 send-sequence 号码的确认段 以及指示下一个预期序列号的确认 将被接收,并且连接保持相同状态。"
.....
“考虑处理传入片段的一种自然方式是 想象一下,他们首先测试了正确的序列号(即, 它们的内容在预期的范围内 "receive window" 在序列号 space) 然后他们通常排队 并按序号顺序处理。
当一个片段与其他已经接收到的片段重叠时,我们会重建 段只包含新数据,并调整 header 字段 保持一致。
...
我的回复: 请记住,如果发生这种情况,那是因为客户端的 bad-behaving TCP。不是针对 out-of-order,而是针对带有 FIN 标志的段中的错误序列。或者可能是攻击。
当服务器端的TCP接收到带有SEQ=201的报文段时,它会将这个报文段存储一段有限的时间,并且会发回一个101的ACK,因为它正在等待那个SEQ号。 那么当SEQ=101的报文段到达时,接收端的TCP在接收到SEQ=101的报文段后会有一个新的receivewindow。从第一个到达的 SEQ=201 段开始,它应该只获取字节 251 之后的数据(在我的测试中,它没有这样做,而是从 SEQ=101 的段中删除了重叠的字节——这可能取决于实现),如果有的话,并接受 FIN。接收方 TCP 将发回一个 ACK。当服务器端关闭套接字时,接收方 TCP 将发回一个 [FIN, ACK] 段。
为了测试它,我有一个完全按照您描述的方式执行的客户端(这是用用户 space 中的原始套接字完成的,不可能用 TCP 套接字模拟它。服务器是一个简单的 nodejs 服务器),发送 FIN 段,15 秒后发送前一个段。服务器读取接收到的数据,并在 10 秒后关闭套接字。
这里是tcpdump,可以看到TCP服务器端响应:
[rodolk@localhost ~]$ sudo tcpdump -i p2p1 -vv tcp
tcpdump: listening on p2p1, link-type EN10MB (Ethernet), capture size 65535 bytes
19:33:03.648216 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [S], cksum 0x5f49 (correct), seq 523645, win 500, length 0
19:33:03.649826 IP (tos 0x0, ttl 128, id 26590, offset 0, flags [DF], proto TCP (6), length 44)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [S.], cksum 0x1ac8 (correct), seq 1576251572, ack 523646, win 8192, options [mss 1460], length 0
19:33:03.651208 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [.], cksum 0x5091 (correct), seq 1, ack 1, win 500, length 0
19:33:03.651567 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 74)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [F.], cksum 0x8121 (correct), seq 122:156, ack 1, win 500, length 34
19:33:03.651891 IP (tos 0x0, ttl 128, id 26591, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [.], cksum 0x5314 (correct), seq 1, ack 1, win 65392, length 0
19:33:18.652083 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 171)
192.168.56.101.16345 > 192.168.56.1.webcache: Flags [P.], cksum 0xf973 (correct), seq 1:132, ack 1, win 500, length 131
19:33:18.652834 IP (tos 0x0, ttl 128, id 26593, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [.], cksum 0x5313 (correct), seq 1, ack 157, win 65237, length 0
19:33:28.661041 IP (tos 0x0, ttl 128, id 26594, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [F.], cksum 0x5312 (correct), seq 1, ack 157, win 65237, length 0
19:33:28.961756 IP (tos 0x0, ttl 128, id 26595, offset 0, flags [DF], proto TCP (6), length 40)
192.168.56.1.webcache > 192.168.56.101.16345: Flags [F.], cksum 0x5312 (correct), seq 1, ack 157, win 65237, length 0