最近一段時間,對網路又開始追根溯源,最好的辦法就是開啟開源協議棧看乙個究竟,不求寫乙個完整的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...