詳解IP首部效檢和 checksum

2021-09-30 08:50:46 字數 2888 閱讀 6817

最近一段時間,對網路又開始追根溯源,最好的辦法就是開啟開源協議棧看乙個究竟,不求寫乙個完整的ip協議棧,但求通達解惑!

眾所周知,ip頭定義如下:

struct ipheader

unsigned char ver_hlen; 

unsigned char tos;

unsigned short len;

unsigned short id;

unsigned short offset;

unsigned char   ttl;

unsigned char   type;

unsigned short   cksum_header;

unsigned long   ipsrc;

unsigned long   ipdest;

後面可能存在option資料

ip頭中的大多欄位都好理解,只要一本tcp/ip入門的書就可以明明白白了,對cksum欄位理解,如果只是看書,到頭來很可能還不清楚怎麼算它!

關於cksum_header的描述在《tcp/ip卷一》中是這樣描述的:

首部檢驗和字段是根據i p 首部計算的檢驗和碼。它不對首部後面的資料進行計算。i c m p 、i g m p 、u d p 和t c p 在它們各自的首部中均含有同時覆蓋首部和資料檢驗和碼。

為了計算乙份資料報的i p 檢驗和,首先把檢驗和字段置為0 。然後,對首部中每個16 bit進行二進位制反碼求和(整個首部看成是由一串16 bit 的字組成),結果存在檢驗和字段中。當收到乙份i p 資料報後,同樣對首部中每個16 bit 進行二進位制反碼的求和。由於接收方在計算過,程中包含了傳送方存在首部中的檢驗和,因此,如果首部在傳輸過程中沒有發生任何差錯,那麼接收方計算的結果應該為全1 。如果結果不是全1 (即檢驗和錯誤),那麼i p 就丟棄收到的資料報。但是不生成差錯報文,由上層去發現丟失的資料報並進行重傳。

不知道有多少能人看完此描述後,寫出演算法或函式來!

正確的函式如下:

unsigned short checksum(unsigned short *szbuf,int isize)

unsigned long cksum=0;

for(;isize>1;isize-=sizeof(unsigned short))

cksum+=*szbuf++;

if(isize==1)

cksum+=*(unsigned char *)szbuf;

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(unsigned short )(~cksum);

讓我們假設乙個ip頭資料,來解cksum的惑!

ip頭資料:

01000101   /*ver_hlen; */

00000000   /*tos*/

00000000 00000010/*len*/

00000000 00000000/*id*/

00000000 00000000/*offset*/

00000001   /*ttl*/

00010001   /*type*/

00000000 00000000/*cksum(0)*/

01111111 00000000 00000000 0000001/*sip*/

01111111 00000000 00000000 0000001/*dip*/

運算過程(注意是大端格式加):

01000101 00000000

和: 101000111 00010101

cksum=(cksum>>16)+(cksum&0xffff)後:

00000000 00000001                1

和: 01000111 00010110

cksum+=(cksum>>16)後:

和: 01000111 00010110

~: 10111000 11101000(效檢和)

運算過程(注意用小端格式加):

00000000 01000101

和: 00010110 01000111

cksum=(cksum>>16)+(cksum&0xffff)後:

和: 00010110 01000111

cksum+=(cksum>>16)後:

和: 00010110 01000111

~: 11101001 10111000(效檢和)

checksum2:11101000 10111000(小端)

checksum1:10111000 11101000(大端)

演算法一樣,說白了就是迴圈加,加到沒有進製為止,然後在取反!

在現在《tcp/ip卷二》中的cksum實現有以下語句:

while(sum>>16)

sum=(sum&0xffff)+(sum>>16);

通過它更能說明就是在作迴圈加操作,現在又有乙個疑問:

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);         

和while(sum>>16)

sum=(sum&0xffff)+(sum>>16);

等價嗎?

等價,在一定條件下等價,大家都知道ip理論上最長是0xffff

那麼checksum最大不會超過:0xffff0000

這樣》16後為0xffff

0xffff+checksum最大0x1fffe,

0x1fffe >>16+0x1fffe=0xffff

注意了沒有了進製

所以得到等價的結論!

以前每讀到cksum註解時,書上只是草草曰16位反碼和之云云,沒有強調進製也要參加運算一點徵兆,直到最近寫了不少程式才看清楚這個細節!

原始碼之下必解惑!

IP首部詳解

4位版本 4 位首部長度 8 位服務型別 tos 16 位總長度 16 位識別符號 3 位標誌 13位片偏移 8 位生存時間 8 位協議 16位首部檢驗和 32 位源ip位址 32位目的 ip位址 32 位選項 若有 資料 首都長度 ip首部的長度,一般為 20b.版本 ip位址的版本,目前我們使用...

IP位址首部詳解

ip位址首部圖示 版本號 version 長度4位元。標識目前採用的ip協議的版本號。一般的值為0100 ipv4 0110 ipv6 ip包頭長度 header length 長度4位元。這個欄位的作用是為了描述ip包頭的長度,因為在ip包頭中有變長的可選部分。該部分佔4個bit位,單位為32bi...

ip首部校驗和計算

ip首部校驗和的計算方法 1.把校驗和字段清零。2.然後對每16位 2位元組 進行二進位制反碼求和,反碼求和的意思是先對每16位求和,再將得到的和轉為反碼。接下來詳細描述反碼求和的步驟 看下面的 演算法 short checksum ushort buffer,int size if size ck...