IP數據報首部checksum的計算
一、首先區別下面兩個概念:
(1)one's complement:正數=原碼,負數=反碼
(2)two's complement:就是通常所指的補碼
二、計算ip首部校驗和
1.發送IP數據報計算checksum
(1)將校驗和字段置為0;
(2)對首部中(一般為20B)每個16位字進行二進制反碼求和;(這里的文字描述是有問題的,每個16bit進行二進制反碼求和,是要把16bit先去反碼再求和嗎?實際上是16bit逐個求和之后,再取反碼的意思)
(3)將(2)中得到的和再取反碼,即得checksum,寫入校驗和字段中。
抓個IP數據包,取IP數據報報頭部分(20B),數據如下:
45 00 00 30 80 4c 40 00 80 06 b5 2e d3 43 11 7b cb 51 15 3d
下面我來計算一下校驗和:
(1)將校驗和字段置為0:
將b5 2e置為00 00,即變成:
45 00 00 30 80 4c 40 00 80 06 00 00 d3 43 11 7b cb 51 15 3d
(2)反碼求和
4500+0030+804c+4000+8006+0000+d343+117b+cb51+153d=34ace
將將進位(3)加到低16位(4ace)上:0003+4ace=4ad1
(3)取反碼
將4ad1取反得:checksum=b52e
2.接收IP數據報檢驗IP校驗和
(1)對首部中每個16 bit進行二進制反碼求和;
(2)將(1)中得到的和再取反碼 ,看是否為0.
接收到的IP數據報首部:
45 00 00 30 80 4c 40 00 80 06 b5 2e d3 43 11 7b cb 51 15 3d
下面來驗證下:
(1)反碼求和
4500+0030+804c+4000+8006+b52e+d343+117b+cb51+153d=3fffc
0003+fffc=ffff
(2)取反碼:~ffff=0 正確
三、求IP數據報首部校驗碼代碼
已將IP首部校驗和0xb52e置為0x0000
#include<stdio.h>
void main()
{
int buff[10]={0x4500,0x0030,0x804c,0x4000,0x8006,0x0000,0xd343,0x117b,0xcb51,0x153d};
int checksum=0,i=0;
for(i=0;i<10;i++)
{
checksum+=buff[i];
}
printf("checksum=%x/n",checksum);
checksum=(checksum>>16)+(checksum & 0xffff);
checksum+=(checksum>>16);
checksum=0xffff-checksum;
printf("checksum=%04x/n",checksum);
}
IP校驗和計算
下面摘自《TCP/IP協議簇》的IP頭校驗和算法:
發送時:
1. 將校驗和字段置為0;
2. 將整個首部分為16bit的部分,求和;
3. 取反碼,填入到校驗和字段中;
接收時:
1. 直接將整個首部分為16bit的部分,求和;
2. 取反碼,若結果為0,取合法;否則丟棄;
這上面有兩個細節沒有描述清楚:
1. 計算時的字節順序(litter endian和big endian)問題;
2. 取和溢出時的改進計算方法;
根據實驗結果,及參考網絡上的資料,實際上幾乎現有所有的系統對校驗和算法已經有點小小的補充,也許《TCP/IP協議簇》這里沒有更新罷了,自我安慰吧,如下:
◆當發送IP包時,需要計算IP報頭的校驗和:
1、 把校驗和字段置為0;
2、 對IP頭部中的每16bit進行二進制求和;
3、 如果和的高16bit不為0,則將和的高16bit和低16bit反復相加,直到和的高16bit為0,從而獲得一個16bit的值;
4、 將該16bit的值取反,存入校驗和字段。
◆當接收IP包時,需要對報頭進行確認,檢查IP頭是否有誤,算法同上2、3步,然后判斷取反的結果是否為0,是則正確,否則有錯。
算法:
