如何启用UDP校验和

6
我正在处理一个涉及VxWorks设备和Linux机器之间的UDP套接字通信项目。在这个项目中,我想利用UDP头文件中的校验和字段。
在VxWorks套接字接口中,默认情况下启用了发出的UDP数据包的校验和字段。
然而,在通常的Unix套接字接口中,似乎没有任何标志或其他方法来打开一个UDP套接字,以检查传入数据包的校验和并为发出的数据包填充校验和。
针对通常的Unix套接字接口,是否存在这样的标志?
谢谢!

如果它不能生成或检查UDP校验和,那么它就不是UDP,而是其他东西。除非你在官方文档中读到vxworks不检查UDP校验和,否则可以安全地假设它会检查。 - nos
@nos 不完全正确。您可以在接口中关闭生成校验和的功能。 - nullptr
@UDPLover 那会关闭网络接口卡本身的循环冗余校验生成,因此操作系统必须代替执行。 - nos
@nos UDP协议规定校验和字段可以具有值0,这意味着未生成校验和,因此接收方不应尝试检查校验和。 - nullptr
@nos是操作系统实现相关的。没有校验和的UDP数据包也是有效的数据包。这取决于接收应用程序。 - nullptr
3个回答

5
我不是专家,但是man 7 udp上唯一提到的事情是它默认启用:

UDP生成和检查校验和以捕获传输错误。

它没有提到任何禁用它的方法。

编辑:我太懒了,不想查找当前内核源代码,但是这个页面表明具有无效校验和的数据包将被简单地丢弃(csum_copy_err部分)。


2
使用IPv4上的UDP,校验和字段在技术上是可选的。如果值为0,则会忽略校验和。然而,IPv6上的UDP需要校验和为非零值,并且具有零校验和的数据报必须被丢弃。如果校验和应该为零,则必须将其发送为FFFF。(在指定IPv6的RFC 2460中查找“UDP校验和”)。 - zneak
校验和会发现错误吗?数据段会在UDP中丢失吗? - Manjitha Teshara

3
(我不是专家。以下可能完全错误。)网络接口(或驱动程序或等效物)应该检查传入数据包的校验和。 全零位的校验和意味着“出站接口没有生成校验和”。 接口必须检查任何其他校验和(包括全一位,即校验字段使用的补码编码中的“负零”),如果未通过检查,则必须丢弃数据包。
因此,您绝不能禁用传入数据包的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(); }


1
关于@zneak的评论,RFC6936现在允许在某些受限制的条件下(例如隧道流量)使用IPv6上的UDP零校验和。Linux为此定义了UDP_NO_CHECK6_TXUDP_NO_CHECK6_RX套接字选项,请参见this commit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接