尝试在原始 IP 数据包上发送数据时的 EMSGSIZE

EMSGSIZE when trying to send data on raw IP packet

我的代码将原始 IP 数据包发送到 12.12.12.12,但由于 EMSGSIZE 而失败。我认为它根据以太网 MTU 限制了我的数据包,但它应该发送数据包 <= 65,535 字节(IPv4 MTU)。

我试过向127.0.0.1发送数据包,效果很好,但是当我向非本地IP发送数据包时出现错误。

#include <assert.h>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void) {
    int fd;
    assert((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(1818);
    assert(inet_aton("12.12.12.12", &addr.sin_addr) != -1);
    assert(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != -1);

    char buffer[2000];
    memset(buffer, '[=10=]', sizeof(buffer));
    assert(send(fd, buffer, sizeof(buffer), 0) == sizeof(buffer));

    assert(close(fd) != -1);
}

我希望代码可以正常运行,因为我发送的数据包小于 IP MTU。使用 strace:

对代码进行故障排除
socket(AF_INET, SOCK_RAW, IPPROTO_RAW)  = 3
connect(3, {sa_family=AF_INET, sin_port=htons(1818), sin_addr=inet_addr("12.12.12.12")}, 16) = 0
sendto(3, "[=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=][=11=]"..., 2000, 0, NULL, 0) = -1 EMSGSIZE (Message too long)
a.out: compile.c:22: main: Assertion `send(fd, buffer, sizeof(buffer), 0) == sizeof(buffer)' failed.
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=8814, si_uid=0} ---
+++ killed by SIGABRT (core dumped) +++
Aborted

I think that it limits my packet according to Ethernet MTU, but it should send packets <= 65,535 bytes (IPv4 MTU).

由于默认情况下 PMTU 处于启用状态,因此它只会发送适合 MTU 的数据包。你的包裹没有。 来自 raw(7):

By default, raw sockets do path MTU (Maximum Transmission Unit) discovery. This means the kernel will keep track of the MTU to a specific target IP address and return EMSGSIZE when a raw packet write exceeds it. When this happens, the application should decrease the packet size.
Path MTU discovery can be also turned off using the IP_MTU_DISCOVER socket option or the /proc/sys/net/ipv4/ip_no_pmtu_disc file, see ip(7) for details. When turned off, raw sockets will fragment outgoing packets that exceed the interface MTU. However, disabling it is not recommended for performance and reliability reasons.