(我不是专家。以下可能完全错误。)网络接口(或驱动程序或等效物)应该检查传入数据包的校验和。 全零位的校验和意味着“出站接口没有生成校验和”。 接口必须检查任何其他校验和(包括全一位,即校验字段使用的补码编码中的“负零”),如果未通过检查,则必须丢弃数据包。
因此,您绝不能禁用传入数据包的UDP校验和检查(如果这些数据包提供了校验和)。 这只是UDP标准的强制性部分。
接收接口可以丢弃没有校验和的数据包,[1]也可以将其传递给应用程序(或可以让应用程序配置其所需的行为,尽管如果可能,我不知道如何做到这一点)。
您唯一可能能够控制的是发送接口是否在出站数据包上生成校验和。 它将是特定于平台的。 我下面收集了一些可能有效的方法; 但要注意。
如果您只是采用平台的默认行为,那么您将默认生成UDP校验和 - 我会打赌。
[1] — RFC 8085:“应用程序可以选择丢弃具有零校验和的UDP数据报[RFC1122]。”
1999年的这篇comp.protocols.tcp-ip帖子建议在Solaris上,您可以通过命令行上的ndd
全局禁用传出数据包的UDP校验和生成:
ndd -set /dev/udp udp_do_checksum 0
ndd
实用程序是专门针对 Solaris 内核的,而在 Linux 或 FreeBSD 上不存在。此外,即使 Solaris 文档 也指出:
udp_do_checksum
This parameter controls whether UDP calculates the checksum
on outgoing UDP/IPv4 packets.
Default
1 (enabled)
When to Change
Do not change this parameter.
在Linux和FreeBSD上,/dev/udp
"并不存在";它是Bash提供的虚构。 我不知道Solaris上/dev/udp
是否"真正存在"。
微软文档 暗示在Windows上,你可以使用一个已记录的选项,在每个套接字基础上以编程方式禁用UDP校验和生成。
DWORD trueValue = 1;
int rc = setsockopt(fd, IPPROTO_UDP, UDP_NOCHECKSUM, (const char*)&yes, sizeof yes);
if (rc != 0) { perror("setsockopt"); abort(); }
这个帖子表明在FreeBSD(例如Mac OS X)上,您可以使用一种否则未记录但截至2018年1月存在的选项,在每个套接字上以编程方式禁用校验和生成:
int yes = 1;
int rc = setsockopt(sock, IPPROTO_UDP, UDP_NOCKSUM, (void*)&yes, sizeof yes);
if (rc != 0) { perror("setsockopt"); abort(); }
最后,
这个线程 表明在Linux上可以通过编程方式基于每个套接字禁用校验和生成,使用一个否则未记录的选项(但截至2018年1月已存在)。
int yes = 1;
int rc = setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, (void*)&yes, sizeof yes);
if (rc != 0) { perror("setsockopt"); abort(); }