UDP校验和计算

时间:2009-09-26 06:29:51

标签: udp checksum

/usr/include/netinet/udp.h中定义的UDP头结构如下

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

标题的检查字段中存储了什么值?如何验证校验和是否正确?我的意思是校验和计算的数据是什么? (它只是udp头或udp头加上它后面的有效负载吗?)

感谢。

3 个答案:

答案 0 :(得分:34)

UDP校验和在整个有效负载上执行,标头中的其他字段,来自IP标头的某些字段。从IP报头构造伪报头以便执行计算(通过该伪报头,UDP报头和有效载荷完成)。包含伪标头的原因是捕获已路由到错误IP地址的数据包。

基本上,在接收端,标题的所有16位字加数据区被加在一起(以16位包裹),并且结果将与0xffff进行核对。

在发送方面,它有点复杂。在所有16位值上执行一个补码和,然后从该值获取一个补码(即,反转所有位)以填充校验和字段(具有计算的校验和为零的额外条件将变为全部一个位)。

一个补码和只是所有一个补码值的总和。它有点复杂。

基本上,你有一个从零开始运行的16位累加器,你将每个16位值加到那里。每当其中一个添加产生进位时,该值就会被包围,并再次向该值添加一个值。这有效地取得了16位加法的进位,并将其加到值上。


  

顺便说一句,这对我来说是纯粹的猜想,但这可能通过使用ADC(with with carry)指令而不是ADD(令人惊讶的是,添加)来有效地完成。 ,或者当时CPU上可用的任何等效指令。

     

如果没有进位,ADC只会从进位中添加零位。在这些东西完成的时候(是的,不幸的是,我那么旧),内存远远超过了速度,而不是现在的情况,所以节省了几个字节你的代码可以很好地将你提升到宇宙的半神 - 皇帝的水平: - )


请注意,您永远不必担心第二次携带(或者如果您正在使用前一段中提到的方法,则使用下一个ADC进行两次携带)因为两个最大的16位值,总和时,生成(从0x1fffe截断)0xfffe - 在其中添加一个将永远不会导致另一个进位。

一旦计算出的一个补码和,它的位被反转并插入到数据包中,这将导致接收端的计算产生0xffff,假设传输中没有错误。

值得注意的是,有效载荷总是被填充以确保有16位字的整数。如果 填充,则长度字段会告诉您实际的长度。

RFC768是详细说明的规范。

答案 1 :(得分:1)

我正在网上搜索一些会计算udp标头的代码(如上所述使用伪ip标头)。

最后我找到了open-bsd dhclient packet.c:

https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sbin/dhclient/packet.c

查看函数assemble_udp_ip_header()

答案 2 :(得分:1)

一个很好且易于理解的UDP校验和计算示例由Gerd Hoffmann完成。

你可以谷歌搜索“net-checksum.c Gerd Hoffmann” 或者在这里查看文件:

https://gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f3

您可以使用net_checksum_tcpudp函数,将UDP有效负载长度,proto,src和dst IP以及UDP有效负载本身提供给它,它将做正确的事情。

最后你必须在校验和上打电话给htons()并且你很好。