【问题标题】:Linux: Raw Sockets Sent Packets Not Received Locally Under KVMLinux:KVM下本地未收到原始套接字发送的数据包
【发布时间】:2014-07-06 15:12:16
【问题描述】:

我一直在尝试使用原始套接字发送 UDP 数据包,但是,本地未接收到发送的数据包。如果发送到远程目的地,则会收到相同的数据包。测试在KVM下进行。同样的测试似乎在 Parallels 下运行。

套接字设置为:

raw_socket = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL));

附加了一个接收过滤器,它被设置为混杂。数据包被正确接收。发送的数据包在 Wireshark 中被接收并正确分析。但是,本地程序(例如 nc -l -u -p ...)没有收到数据包。如果我将相同的数据包发送到远程目的地,则会正确接收数据包。 Wireshark 收到数据包的事实表明它没有被任何 iptables 规则丢弃(我还检查了所有 DROP 规则计数器并且没有丢弃数据包)。

看起来好像数据包被路由但没有被网络堆栈重新处理,如果这甚至有意义的话。

它应该是网络课程中的示例代码,目前,我在学生面前丢脸。希望他们都不在这个名单上;-)。

不胜感激, 尤瓦尔。

关于代码的一些知识。为简洁起见,UDP 校验和设置为 0,IP 校验和从报头计算。两者都由 Wireshark 验证(也被 KVM 上的远程机器接受)。该代码解析消息并在收到的缓冲区上发送回复。 udp_hdr 和 ip_hdr 指向包缓冲区(buffer)中对应的headers,而payload指向L7数据的开始。

代码如下: { /* 处理请求。 */ ssize_t msg_len; int max_len = sizeof (buffer) - (payload - buffer); 诠释 tmp_port; in_addr_t tmp_ip; struct ether_addr tmp_ether;

        msg_len = parse_and_send (ctx, payload, size, max_len);
        if (msg_len < 0)
        {
           /* Error */
           error_print (ctx, "Failed to parse and construct answer.");
       continue;
        }
        if (msg_len == 0)
        {
           /* No message to send. */
           continue;
        }

        /* Switch sources & destinations and update payload lengths. */
        tmp_port = udp_hdr->dest;
        udp_hdr->dest = udp_hdr->source;
        udp_hdr->source = tmp_port;
        udp_hdr->len = htons (msg_len +
                              (payload - (const uint8_t*) udp_hdr));
        tmp_ip = ip_hdr->daddr;
        compute_udp_cksum (udp_hdr);

        ip_hdr->daddr = ip_hdr->saddr;
    ip_hdr->saddr = tmp_ip;
        ip_hdr->tot_len = htons (msg_len +
                                 (payload - (const uint8_t*) ip_hdr));
        compute_ip_cksum (ip_hdr);

        memcpy (tmp_ether.ether_addr_octet, ether_hdr->ether_dhost,
                sizeof (tmp_ether));
        memcpy (ether_hdr->ether_dhost, ether_hdr->ether_shost, ETH_ALEN);
        memcpy (ether_hdr->ether_shost, tmp_ether.ether_addr_octet,
                sizeof (tmp_ether));

        if (sendto (ctx->raw_socket,
                    &buffer, msg_len + (payload - buffer), 0,
                    (struct sockaddr*) &ll_addr, sizeof (ll_addr)) < 0)
        {
           ERROR_SYSTEM (ctx, "Sending packet");
           error_print (ctx, "Failed to send packet");
       continue;
        }
     }

【问题讨论】:

  • 如果数据包被 Wireshark 接收到,并不意味着它们没有被丢弃;但如果你检查了它就可以了。请准确提及您用于在 shell 中接收数据包的命令。
  • 为了简单起见,我使用了 nc -l -u -p 2222。在远程机器上它工作正常。在本地机器上(使用原始套接字),什么都没有收到。
  • 你能给出你用来发送数据包的代码吗?
  • 代码如下:
  • 显然这是上面的代码。无法将代码放入评论中...谢谢。

标签: linux sockets networking


【解决方案1】:

让我们写下我们知道的事实:

1- 你说你可以在抓包程序(例如 Wireshark)中看到数据包

2- 当你发送数据包到 环回接口。

3- 当您将数据包发送到远程机器时,您告诉过您可以接收数据包。

所以问题出在您的代码或本地机器上。我有很多建议:

1- 在另一台机器上测试代码,并将数据包发送到环回接口并尝试使用 netcat 捕获它们。

2-尝试使用netcat向本地接口发送一堆UDP数据包并使用另一个netcat实例接收它们并检查它是否有效;如果它有效,您就知道问题出在您的代码中,否则问题可能出在您的本地机器上。

【讨论】:

  • 谢谢,我知道问题出在我的代码和 KVM/OpenStack 的组合上。它适用于具有相同 VM 的 Parallels,因此这不是 Linux 问题。我也知道使用相同的代码将数据包发送到另一台机器,数据包会通过。我想找到答案的唯一方法是通过内核跟踪数据包。我对学生的解决方案是将数据包发送到另一台机器:-)。尤瓦尔。附言很抱歉花了很长时间才回答,我不在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 2019-08-02
  • 1970-01-01
  • 2022-01-01
  • 2018-11-16
  • 2019-11-28
相关资源
最近更新 更多