如何启用UDP校验和

时间:2012-12-26 17:02:56

标签: c sockets network-programming udp checksum

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

在VxWorks套接字界面中,默认情况下启用传出UDP数据包的checksum字段。

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

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

谢谢!

3 个答案:

答案 0 :(得分:6)

我不是专家,但man 7 udp在此问题上唯一要说的是默认启用它:

  

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

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

编辑:我懒得查找当前的内核源代码,但是this page表示只删除了校验和无效的数据包(csum_copy_err部分)。

答案 1 :(得分:0)

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

网络接口(或驱动程序或类似的东西)应该检查传入数据包的校验和。所有位零的校验和意味着"输出接口没有生成校验和。"接口必须检查任何其他校验和(包括所有位 - 一,也就是"负零"在校验和字段使用的补码编码中)并且如果检查失败则必须丢弃该数据包。

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

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

您可能能够控制的唯一事情是发送接口是否在传出数据包上生成校验和。它将是特定于平台的。我已经收集了以下一些方法,这些方式可能会也可能不会起作用;告诫lector。

如果您只是采用平台的默认行为,默认情况下会生成UDP校验和 - 我会在其上投入资金。

  

[1] - RFC 8085:"允许应用程序可选地丢弃校验和为零的UDP数据报[RFC1122]。"

This comp.protocols.tcp-ip post from 1999建议在Solaris上,您可以在命令行上通过ndd全局禁止在传出数据包上生成UDP校验和:

ndd -set /dev/udp udp_do_checksum 0

ndd实用程序特定于Solaris内核,在Linux或FreeBSD上不存在。此外,即使the Solaris docs说:

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 "doesn't really exist"; it's a fiction provided by Bash.我不知道/dev/udp"是否确实存在"在Solaris上。)

Microsoft's docs暗示在Windows上,您可以使用记录的选项以编程方式在每个套接字上禁用UDP校验和生成:

DWORD trueValue = 1;
int rc = setsockopt(fd, IPPROTO_UDP, UDP_NOCHECKSUM, (const char*)&yes, sizeof yes);
if (rc != 0) { perror("setsockopt"); abort(); }

This thread意味着在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(); }

最后,this thread意味着在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(); }

答案 2 :(得分:0)

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