IP头校验和
IP数据包的头信息格式:
+-------------------------------------------------+
| 版本 (4位) |
+-------------------------------------------------+
| 首部长度(4位) |
+-------------------------------------------------+
| 服务类型(TOS)8位 |
+-------------------------------------------------+
| 数据包总长度(16位) |
+-------------------------------------------------+
| 标识ID号(16位) |
+-------------------------------------------------+
| 标志位(3位) |
+-------------------------------------------------+
| 片偏移(13位) |
+-------------------------------------------------+
| 生存时间(TTL)(8位) |
+-------------------------------------------------+
| 协议类型 (8位) |
+-------------------------------------------------+
| 首部校验和(16位) |
+-------------------------------------------------+
| 源IP地址(32位) |
+-------------------------------------------------+
| 目的IP地址 (32位) |
+-------------------------------------------------+
* IP选项(若有) (32位) *
+-------------------------------------------------+
* 数据 *
+-------------------------------------------------+
这里要说的是首部校验和字段。
在发送数据时,为了计算数IP据报的校验和。应该按如下步骤:
(1)把IP数据报的首部都置为0,包括校验和字段。
(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和。
(3)把得到的结果存入校验和字段中。
在接收数据时,计算数据报的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。
(2)检查计算出的校验和的结果是否等于零。
(3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包
二进制反码求和:先进行二进制求和,然后对和取反
计算对IP首部检验和的算法如下:
(1)把IP数据包的校验和字段置为0;
(2)把首部看成以16位为单位的数字组成,依次进行二进制求和(注意:求和时应将最高位的进位保存,所以加法应采用32位加法);
(3)将上述加法过程中产生的进位(最高位的进位)加到低16位(采用32位加法时,即为将高16位与低16位相加,之后还要把该次加法最高位产生的进位加到低16位)
(4)将上述的和取反,即得到校验和。
程序如下:
unsigned short ipCksum(unsigned short *addr,int len)
{
unsigned short cksum;
unsigned int sum=0;
while(len>1)
{
sum+=*addr++;
len-=2;
}
if(len==1)
sum+=*(unsigned char*)addr;
sum=(sum>>16)+(sum&0xffff); //把高位的进位,加到低八位,其实是32位加法
sum+=(sum>>16); //add carry
cksum=~sum; //取反
return (cksum);
}
int main()
{
unsigned short iph[]={0x4500,0x00ad,0x7755,0x4000,0x8006,
0x0000,0x0a97,0x7819,0x0a97,0x781d};
unsigned short cksum;
cksum=ipCksum(iph,20);
printf("%X\n",cksum);
iph[5]=cksum;
cksum=ipCksum(iph,20);
if(cksum)
printf("Checksum is incorrect!\n");
else
printf("Checksum is correct!\n");
}
浙公网安备 33010602011771号