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