我们正在尝试分析各种TCP实现的行为(Windows 8,Ubuntu 13.10)。为此,我们使用Scapy,这是一个Python工具,您可以使用它来制作数据包,通过网络发送数据并分析响应。
在我们的设置中,我们有一个假的Scapy指导客户端和一个监听服务器。通过客户端,我们将一系列TCP数据包发送到服务器并检查响应。服务器只接受连接并且不对它们执行任何操作。目的是获得一个简单但更具体的服务器行为模型。我们从模型中忽略/忽略复杂性,例如重传,窗口甚至数据交换。
在Windows 8上分析监听服务器的行为时,我们得到了一个非常好的模型。 然而,在Ubuntu上进行试验时,我们遇到了非确定性行为,至少对我来说很难解释。我在这里附上了wireshark日志的图片,其中包含几个"运行"类似的输入包。每次运行都是通过每次运行增加的端口执行的。 奇怪的情况遵循以下模式:
client ---- SYN 0 _ ---> server [LISTENING]
client <- SYN+ACK 0 1 -- server [SYN_RCVD]
client -- ACK+FIN 1 1 -> server [SYN_RCVD]
client <--- ACK 1 2 ---- server [CLOSE_WAIT]
client ---- ACK 1 20 --> server [CLOSE_WAIT]
client <--- ACK 1 2 ---- server [CLOSE_WAIT] or no_response [CLOSE_WAIT]
有人可以向我解释,为什么收到无效的确认(从未存在的段的确认)服务器的行为是否具有非确定性?也就是说,通过重新发送它为ACK + FIN发送的ACK,或者不发送任何内容。此行为是否由配置参数引起?在我们的设置中,我们使用默认设置。
BTW,简单的服务器代码:
while (true) {
try {
Socket socket = server.accept();
}
catch (IOException e) {}
}
更新
我分析了模型,对于Windows 8,当运行相同的序列时,我得到了超时。这不符合明确指定的rfc793标准:
如果连接处于同步状态(ESTABLISHED, FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT), 任何不可接受的段(窗口序列号或 不易察觉的确认号码)必须只引出一个空的 包含当前发送序列号的确认段 以及表示预期的下一个序列号的确认 被接收,并且连接保持相同状态。
你们有些人可以对此有所了解吗?协议实现是否符合标准,或者是否存在一定程度的不合规。我猜其中一些是不可避免的,因为标准有时未能指定时间限制,但在这里我们讨论的是控制流程中的不合规。
显然我有可能做错了。 :)
保罗,谢谢。答案 0 :(得分:1)
您的服务器是用Java编写的吗?我猜您观察到的“非确定性”是由于GC定时,如果您明确地致电Socket#close()
或等待InputStream#read()
,可能会消失。
答案 1 :(得分:0)
对任何有兴趣的人,我估计我设法追查“问题”。这是一个小规模的不符合规范,应该修复。如果您检查处理收到的细分受众群数量的代码(可用here),则会检查确认号码的可接受性,如rfc 793和rfc 5961中所述。
基于构建于793的rfc 5961,只有在((SND.UNA-MAX.SND.WND)&lt; = SEG.ACK&lt; = SND.NXT)内时,ack编号才可接受。在所有其他情况下,ack编号被认为是不可接受的,应该发出ACK。
在代码本身中,仅针对落入区间的段((SND.UNA-(2 ^ 31-1))&lt; = SEG.ACK&lt; SND.UNA - MAX.SND.WND发出ACK )。如果该段在((SND.NXT + 1&lt; = SEG.ACK&lt; = SND.UNA-2 ^ 31)内,则它们丢弃该段而不发回ACK,即使在这种情况下该段也具有无效的确认号码。发布以下代码的片段。干杯。
/* If the ack is older than previous acks
* then we can probably ignore it.
*/
if (before(ack, prior_snd_una)) {
/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
if (before(ack, prior_snd_una - tp->max_window)) {
tcp_send_challenge_ack(sk);
return -1;
}
goto old_ack;
}
/* If the ack includes data we haven't sent yet, discard
* this segment (RFC793 Section 3.9).
*/
if (after(ack, tp->snd_nxt))
goto invalid_ack;