【问题标题】:Retransmitting large packets with raw sockets使用原始套接字重新传输大数据包
【发布时间】:2017-03-27 16:37:45
【问题描述】:

问题:在原始套接字上,recvfrom 可以捕获比sendto 可以发送更多的字节,从而阻止我重新传输大于 MTU 的数据包。

背景:我正在编写一个将捕获和重新传输数据包的应用程序。基本上主机 A 向 X 发送数据,记录它们并将它们转发给 B,所有 Linux 机器。我正在使用原始套接字,因此我可以捕获所有数据,并且它是使用 socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) 创建的。

然后,有代码等待并读取传入的数据包:

const int buffer_size = 2048;
uint8_t* buffer = new uint8_t[buffer_size];
sockaddr_ll addr = {0};
socklen_t addr_len = sizeof(addr);
int received_bytes = recvfrom(_raw_socket, buffer, buffer_size, 0, (struct sockaddr*)&addr, &addr_len);

随后进行数据包处理,循环结束,再次发送数据包:

struct sockaddr_ll addr;
memset(&addr, 0, sizeof(struct sockaddr_ll));
addr.sll_family = htons(AF_PACKET);
addr.sll_protocol = eth_hdr->type;
addr.sll_ifindex = interface().id();
addr.sll_halen = HardwareAddress::byte_size;
memcpy(&(addr.sll_addr), eth_hdr->dest_mac, HardwareAddress::byte_size);

// Try to send packet
if(sendto(raw_socket(), data, length, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0)

问题是我不希望收到大于以太网 MTU(1500 字节)的数据包,而且我不应该收到,因为我使用的是单独处理每个数据包的原始套接字。但有时我确实收到大于 MTU 的数据包。我认为这可能是我的代码中的错误,但 Wireshark 确认如图所示,因此必须在较低级别进行一些重组,例如网络控制器本身。

好吧,好吧,那么我认为没有办法仅对一个应用程序禁用此功能,而且我无法更改主机配置,因此我可能会增加缓冲区大小。但问题是,当我使用大于 MTU 大小(实际上是 1514B,因为 eth 标头)调用 sendto 时,我得到 80: Message too long errno。这就是上面提到的问题——我不能发送我收到的同一个数据包。对此有什么可能的解决方案?我需要多大的缓冲区才能始终捕获整个数据包?

编辑:我刚刚检查了带有ethtool -k interf 的机器并在所有这些机器上都得到了tcp-segmentation-offload: on,所以看起来它真的是网卡重组碎片。但我想知道为什么sendto 的行为不像recvfrom。如果数据包可以自动重组,为什么不分片呢?

附注:应用程序需要发送这些数据包。使用 iptables 等设置转发将不起作用。

【问题讨论】:

    标签: c linux sockets networking ethernet


    【解决方案1】:

    您的网卡可能启用了分段卸载,这意味着硬件可以在 TCP 分段到达操作系统或您的代码之前重新组装它们。

    您可以通过运行ethtool -k 来检查是否是这种情况。 虽然透明地捕获 TCP 流量并在如此低的级别重新传输它通常比它的价值更麻烦(通常最好在应用层执行此操作,终止 TCP 连接并为您的主机建立一个新的 TCP 连接B),如果您的网卡与数据包混淆,您将无法捕获并重新发送数据包。您需要:

    • 关闭通用分段卸载
    • 关闭通用接收卸载
    • 关闭 tcp-segmentation-offload
    • 如果您还要处理 UDP,请关闭 udp-fragmentation-offload
    • 如果您的数据包是 VLAN 封装的,请关闭 rx-vlan-offload/tx-vlan-offload
    • 可能关闭 rx-checksumming 和 tx-checksumming。如果两者都有效 已启用,或者它已损坏。 RAW 套接字(如果启用),取决于您的 内核版本和网卡类型。

    这些可以使用ethtool -K 命令打开/关闭,具体语法在 ethtool 手册页中描述。

    【讨论】:

    • 我刚刚写了一个与您确认卸载的答案平行的编辑。 1)除了重新配置主机没有其他方法吗? 2) 为什么recvfrom 在卸载时“工作”,而sendto 却不行?我希望如果某些东西可以自动重新组装,它也可以是碎片化的。
    • 好的。好吧,我认为发送端的卸载(如果 NIC 完全支持 ifg)是操作系统 TCP/IP 堆栈和硬件之间的良好交互,这是您仅使用原始套接字无法获得的优势。
    猜你喜欢
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    相关资源
    最近更新 更多