如何计算UDP/TCP检验和checksum
一、下面的图是一个UDP的检验和所需要用到的所有信息,包括三个部分:
UDP伪首部
2.UDP首部
3.UDP的数据部分(切记不要遗漏该部分,否则就~吐血了~)
首先解释下伪首部的概念,伪首部包含IP首部一些字段。其目的是让UDP两次检查数据是否已经正确到达目的地,只是单纯为了做校验用的。
还有一个概念十分重要,那就是16位UDP总长度,请注意该长度不是报文的总长度,而只是UDP(包括UDP头和数据部分)的总长度(之前就是因为这个概念没弄清楚,走了不少弯路,吐血~~)。
二、计算检验和(checksum)的过程很关键,主要分为以下几个步骤:
把伪首部添加到UDP上;
2.计算初始时是需要将检验和字段添零的;
3.把所有位划分为16位(2字节)的字
4.把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上,举例,0xBB5E+0xFCED=0x1 B84B,则将1放到最低位,得到结果是0xB84C
5.将所有字相加得到的结果应该为一个16位的数,将该数取反则可以得到检验和checksum。
三、事实胜于雄辩,还是举个例子来分析一下吧,该例子计算的是一个TCP的检验和(和UDP的算法一致)
TCP计算检验和的报文结构如下所示:
抓包工具抓了一个TCP 的syn报文做研究,呵呵,下面就是整个报文:
首先将检验和部分添零;
2.然后将TCP伪首部部分,TCP首部部分,数据部分都划分成16位的一个个16进制数;
3.将这些数逐个相加,记得溢出的部分加到最低位上,这是循环加法:
0xc0a8+ 0x0166+……+0x0402=0x9b49
4.最后将得到的结果取反,则可以得到检验和位0x64B6
按照上述步骤进行计算就可以得到检验和为0x64B6,大家也可以试试看
IP数据报只检验IP数据报的首部,但UDP检验的是把首部和数据部分一起都检验。
checksum的算法没有必然的,不同人的算法不一定一样。最简单的:全部字节直接相加,按最大字节数取模。
比较通用的:CRC,这个比较复杂,需要上网找专业的资料学习,或者网上应该有算法代码。
总之,checksum应该要通信双方协议好算法,才可以进行校验。
“
协议层的首部里都会有一个校验字段checksum,由发送端计算和存储,由接收端验证,用来保证报文在传输过程中的完整性
checksum的计算方法多样,而对于IP Header和ICMP Header中的checksum,采用相同的计算方法-加法校验和算法
”
计算校验和
IP Header中的checksum 只校验IP首部 ,不校验数据部分
ICMP Header中的checksum 校验ICMP首部和数据部分
反码求和法
“
反码求和法,是先求和,然后再取反
”
发送时
将校验和字段设置为0
每16个bit(即2个字节)组成一个数,相加
取反码,填入校验和字段
书上或网上都这样描述,大致是没错的,但是实际经不起推敲,有一些细节并没有关注到
比如不管是IP Header还是ICMP Header中的checksum都是16个bit,而这些数字相加有可能超过16个bit,怎么办?难道只是简单地把高位数字省略?
当然不是
IP首部的checksum只计算IP首部的数据20个字节,每两个字节组成一个数,这当然比较好分配
然而像ICMP首部中的checksum计算的是首部和数据部分,有可能有奇数个字节,每2个字节组成一个数,最后还会剩下一个字节,这最后一个字节是简单地相加吗?
当然也不是(尤其这个问题,让我搞了很久)
所以总结下计算方法
“
将校验和字段设置为0
每16个bit(即2个字节)组成一个数,相加,如果超过16个bit,把超过的高位值加到这16个bit值上,得到的新值再和下一个值相加
如果最后还剩8个bit值,不能简单的加到低位,要把这8个bit当成高位值,再用0填充一个16个bit值,相加
最后取反,填充到校验和字段
”
capl如何计算
word GetOrVerifyChecksumValue(byte data[], long length)
{
int i = 0
dword temp = 0
word checksum = 0
while (i <length)
{
if ((i+1) <length)
{
temp = checksum + ((data[i]<<8) + data[i+1])
checksum = (temp &0xffff) + (temp >>16)
i = i + 2
}
else
{
temp = checksum + (data[i] <<8)
checksum = (temp &0xffff) + (temp >>16)
i = i + 1
}
}
checksum = ~checksum
return checksum
}
注意:
“
(data[i]<<8)一定要加括号,不然会先计算后面的加号
”
验证校验和
验证校验和的方法也就简单明了了
把校验和值填入校验和字段
每16个bit组成一个数,相加,如果超过16个bit,把超过的加到低位,得到的新值再和下一个值相加
最后的结果为0,说明所有的值都是正确的
如果用capl函数表示,和上面的函数相同,只是计算时要把校验和字段设置为0,返回值是校验和,验证时要把校验和字段设置checksum值,返回值是0
了解这个有什么好处?
“
capl中提供了方法组装报文,校验和会自动计算出,不需要手动计算,但是,在应用层有可能有一些自定义协议,如果采用了这种算法,就需要自己手动计算了
”
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)