IP/ICMP/IGMP/TCP/UDP等协议的校验和算法都是相同的,算法如下:
在发送数据时,为了计算IP数据包的校验和。应该按如下步骤:
(1)把IP数据包的校验和字段置为0;
(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和;
(3)把得到的结果存入校验和字段中。
在接收数据时,计算数据包的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
(2)检查计算出的校验和的结果是否等于零(反码应为16个1);
(3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
所谓的二进制反码求和,即为先进行二进制求和,然后对和取反。
IP数据报格式
最后对上述过程举个例子:
IP头:
45 00 00 31
89 F5 00 00
6E 06 00 00(校验字段)
DE B7 45 5D -> 222.183.69.93
C0 A8 00 DC -> 192.168.0.220
计算:
4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4
0003 + 22C4 = 22C7
~22C7 = DD38 ->即为应填充的校验和
当接受到IP数据包时,要检查IP头是否正确,则对IP头进行检验,方法同上:
计算:
4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC
0003 + FFFC = FFFF
得到的结果是全一,正确。
代码实现
SHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum>>16) + (cksum&0xffff);
cksum += (cksum>>16);
return (USHORT)(~cksum);
}
原文地址:http://12064608.blog.51cto.com/12054608/1888233