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");
}

 

 

posted @ 2012-06-08 16:52  always on the way  阅读(10049)  评论(0编辑  收藏  举报