2009-09-26 321 views
18

在/usr/include/netinet/udp.h定义的UDP报头结构是如下UDP校验和计算

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

什么值被存储在所述报头的校验字段?如何验证校验和是否正确?我的意思是校验和计算的数据是什么? (它只是udp头或udp头加上后面的有效载荷?)

谢谢。

回答

27

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

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

在发送方面,它稍微复杂一些。对所有16位值执行1的补码和,然后用补码(即,反转所有位)取该值来填充校验和字段(附加条件是计算的零校验和将被改变为全部一个位)。

1的补数是而不是只是所有补码值的总和。这有点复杂。

基本上,您有一个从零开始的运行16位累加器,并且您将每个16位值添加到该位。每当这些添加中的一个导致进位时,该值将被缠绕,并且再次为该值添加一个值。这有效地采用16位加法的进位并将其添加到该值。


顺便说一句,这是我的一部分纯粹是主观臆测,但这很可能通过使用ADC来高效地完成(进位加)指令,而不是ADD(令人惊讶的是,添加),或无论您在当时的CPU上有何等效的指令。

如果没有进位,ADC只会增加进位的零位。在完成这些工作的时代(不幸的是,我认为这是旧的),内存与速度相比,更多地是一个制约因素,而不是现在的情况,因此在代码中保存几个字节可能会提升你到半神皇帝的最宇宙的:-)


注意的水平,你从来没有担心随身携带的第二次(或两个与下进ADC如果您使用前一段中提到的方法),因为两个最大的16位值在求和时产生(从0x1fffe截取)0xfffe - 向其中添加一个永远不会导致另一个进位。

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

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

RFC768是详细说明这一点的规范。

+0

谢谢你。我对Pseudo-Header部分有些困惑......但是RFC清除了空气。 “ – Deepak 2009-09-26 07:03:48

+1

”所有标题的16位字(其中UDP校验和为零)被添加,并且补码(即,反转所有位)被放入校验和字段中。“不,RFC说什么会导致“所有人的头补充(即反转所有比特)的头(UDP校验和为零)的16位字被添加,并且这个补码是什么得到了进入校验和字段“。 否则完美答案+1。 – Joren 2009-09-26 07:17:57

+1

这是不对的。 “补数和”并不意味着取每个词的补码并将它们加在一起。这意味着你将这些单词加在一起,并且当一个进位位被产生时,你给运行总和加1。参见http://mathforum.org/library/drmath/view/54379.html。 – 2010-04-22 15:51:03

1

一个很好的和容易理解的例子UDP校验和计算是由格尔德·霍夫曼做。

您可以谷歌“网checksum.c格尔德·霍夫曼” 或看这里的文件:

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

可以使用net_checksum_tcpudp功能,给它的UDP有效载荷长度,原,SRC和dst IP,然后是UDP有效载荷本身,它会做正确的事情。

最后你必须在校验码上拨打htons(),你很好。