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