6

我正在从事一个涉及 VxWorks 设备和 Linux 机器之间的 UDP 套接字通信的项目。在这个项目中,我想利用 UDP 标头的校验和字段。

似乎在 VxWorks 套接字接口中,checksum默认启用了传出 UDP 数据包字段。

但是,对于通常的 Unix 套接字接口,似乎没有任何标志或其他方法可以打开 UDP 套接字来检查传入数据包的校验和并为传出数据包填充它。

对于通常的 Unix 套接字接口,是否存在这样的标志?

谢谢!

4

3 回答 3

5

我不是专家,但在这件事上唯一man 7 udp要说的是它默认启用:

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

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

编辑:我懒得去查找当前的内核源代码,但是这个页面建议带有无效校验和的数据包被简单地丢弃(csum_copy_err部分)。

于 2012-12-26T17:12:18.477 回答
2

(我不是专家。以下可能完全错误。)

网络接口(或驱动程序或类似的东西)应该检查传入数据包的校验和。所有位为零的校验和表示“传出接口未生成校验和”。接口必须检查任何其他校验和(包括所有位为 1,也就是校验和字段使用的补码编码中的“负零”),如果检查失败,则必须丢弃数据包。

因此,您永远不能禁用对传入数据包的 UDP 校验和检查(如果这些数据包提供了校验和)。这只是 UDP 标准的强制性部分。

接收接口可以丢弃没有校验和的数据包,[1]或者可以将它们传递给应用程序(或者可以让应用程序配置其所需的行为,尽管如果可能的话,我不知道该怎么做)。

您唯一可能能够控制的是发送接口是否在传出数据包上生成校验和。它将是特定于平台的。我在下面收集了一些方法,它们可能有效,也可能无效;警告讲师。

如果您只是采用您平台的默认行为,您将默认生成 UDP 校验和——我会在上面投入资金。

[1] — RFC 8085:“允许应用程序选择性地丢弃校验和为零的 UDP 数据报 [ RFC1122 ]。”


这篇 1999 年的 comp.protocols.tcp-ip 帖子ndd表明,在 Solaris 上,您可以通过命令行全局禁用对传出数据包生成 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 提供的虚构。我不知道/dev/udp在 Solaris 上是否“真正存在”。)


Microsoft 的文档暗示,在 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(); }

于 2018-01-02T22:02:35.390 回答
1

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

于 2019-01-18T09:29:26.887 回答