【问题标题】:Linux TCP strange behaviorLinux TCP 奇怪的行为
【发布时间】:2014-04-14 19:17:33
【问题描述】:

我们正在尝试分析各种 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,要么不发送任何东西。这种行为是由配置参数引起的吗?在我们的设置中,我们使用默认设置。

顺便说一句,简单的服务器代码:

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), 任何不可接受的段(超出窗口的序列号或 不可接受的确认号)必须只引出一个空的 包含当前发送序列号的确认段 以及指示下一个预期序列号的确认 被接收,并且连接保持在相同的状态。

你们中的一些人能对此有所了解吗?协议实现是为了符合标准还是有一定程度的不符合标准。我想其中一些是不可避免的,因为标准有时无法指定时间限制,但这里我们谈论的是控制流中的不合规性。

显然我做错了什么的可能性仍然存在。 :)

谢谢,保罗。

【问题讨论】:

  • 错误,一个错误?显然,它应该重新发送它发送的最后一个 ACK​​。 NB 状态是 CLOSE_WAIT,而不是 CLOSED_WAIT。本地端口根本没有关闭,关键是它正在等待关闭。
  • 我的错,确实是CLOSE_WAIT,是的,端口没有关闭。我会相应地更新我的帖子。我同意你的看法,我所期望的行为是重新发送之前的 ACK。我想知道 Wireshark 是否丢失/没有看到那些 ACK 数据包。我从 Ubuntu 12.04 LTS 和 Ubuntu 13.10 得到了相同的行为。

标签: python linux networking tcp scapy


【解决方案1】:

您的服务器是用 Java 编写的吗?我猜您观察到的“不确定性”是由于 GC 计时造成的,如果您明确调用 Socket#close() 或等待 InputStream#read(),可能会消失。

【讨论】:

  • 抱歉回复晚了,通过调用 close 我会从服务器端触发 FIN+ACK。这个实验的重点是让服务器完全反应。我相信,但我不是专家,垃圾收集器不会施加任何影响,因为我们正在谈论操作系统级别的实现。除非正确终止,否则连接将比 java 服务器端的相应句柄保持更长的时间。 (在这种情况下,句柄什么都不是,因为在服务器端我们只接受)
  • 回首往事,我不得不道歉并说您提出了一个有效的观点。垃圾收集确实会清除打开且未引用的套接字(删除文件描述符)。
【解决方案2】:

对于任何感兴趣的人,我认为我设法找到了“问题”。这是一个小的不符合规范的问题,应该修复。如果您检查用于处理收到的段的确认号的代码(可用here),则会检查确认号的可接受性,如rfc 793rfc 5961 中所述。

基于 rfc 5961,它建立在 793 之上,只有在 ((SND.UNA - MAX.SND.WND)

在代码本身中,ACK 仅对落在区间 ((SND.UNA-(2^31-1))

 /* 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;

【讨论】:

    猜你喜欢
    • 2021-05-22
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多