**:
校驗和演算法
之前一直只知道ip校驗和演算法反碼求和相關的,但具體細節不清楚,今天了解了下。
ip校驗和主要是用來保證資料(ip包頭)的完整性的.它用的演算法非常簡單,就是反碼求和校驗.需要注意的是反碼求和又叫1的補碼(one's complement),而2的補碼就是我們通常說的補碼求和了.校驗演算法具體如下.
1、傳送方
i)將校驗和字段置為0,然後將ip包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算(即高位溢位位會加到低位,通常的補碼運算是直接丟掉溢位的高位),將得到的和的反碼填入校驗和字段;
iii)傳送資料報;
2、接收方
i)將ip包頭按16位元分成多個單元,如包頭長度不是16位元的倍數,則用0位元填充到16位元的倍數;
ii)對各個單元採用反碼加法運算,檢查得到的和是否符合是全1(有的實現可能對得到的和會取反碼,然後判斷最終值是不是全0);
iii)如果是全1則進行下步處理,否則意味著包已變化從而丟棄之.
需要強調的是反碼和是採用高位溢位加到低位的,如3位元的反碼和運算:100b+101b=010b(因為100b+101b=1001b,高位溢位1,其應該加到低位,即001b+1b(高位溢位位)=010b),具體細節請參考文章:
二、 校驗和原始碼
網上流傳多組實現,常見的有如下兩種(如追求效率可改寫為彙編**):
1、rfc1071原始碼
unsigned short csum(unsigned char *addr, int count)
/* add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
第乙個while迴圈是做普通加法(2進製補碼加法),因為ip包頭和tcp整個報文段比較短(沒達到2^17數量級),所以不可能導致4位元組的sum溢位(unsigned long 一般至少為4位元組)).
緊接著的乙個判斷語句是為了能處理輸入資料是奇數個位元組的這種情況.
再接著的資料迴圈是實現反碼演算法(在前面的普通加法得到的資料的基礎上),由反碼和的高位溢位加到低位的性質,可得到"32位的資料的高位位元移位16位元,再加上原來的低16位元,不影響最終結果"這個等價運算,因為sum的最初值(剛開始迴圈時)可能很大,所以這個等價運算需迴圈進行,直到sum的高位元(16位元以上)全為0.對於32位的sum,事實上這個運算迴圈至多只有兩輪,所以也有程式直接用兩條"sum = (sum & 0xffff) + (sum >> 16);"代替了整個迴圈.
最後,對和取反返回.
2、對資料長度沒限制的實現
unsigned short cksum (struct ip *ip, int len)
if ( len ) /* take care of left over byte */
sum += ( unsigned short ) * (unsignedl char *) ip;
while ( sum >> 16)
sum =(sum & 0xffff) + (sum>> 16);
return ~sum;
}
這個實現與前面的乙個的最大的不同是對資料的長度沒什麼限制了,因為它在第乙個迴圈的加法運算中實時檢測sum的高位的值,一旦發現其有溢位的危險,就及時運用等價運算關係消除了這個危險.
三、幾個細節問題
1、資料部分改變時的重校驗
考慮這樣的應用場景:路由器**ip報文時,有可能只更改了ip資料報頭的部分內容(如更改了ttl,分片了或snat更改了源ip等~~~),卻需要重校驗的問題.為提高**效率,要求重校驗演算法盡可能快,故出現了如下所示的重校驗演算法(只是乙個簡單的示例):
updatettl(
struct ip_hdr *ipptr
,
unsigned char n
)
演算法的實現依據是這樣的.假設包頭原校驗和為~c,改變的字段的原始值是m,更改後的值是m',設~c'為重校驗和,則有 ~c' = ~(c+(-m)+m') = ~c+(m-m') = ~c+m+~m'
等價關係的成立基於反碼的運算性質:取反運算滿足結合律,按位取反運算與符號取反(及相反數)是等價的(即~c=-c).
如果有多個字段改變,只是上面的公式中的m和m'有多個而已,直接用反碼加法搞定即可。
2、為什麼採用反碼和運算
ip資料報校驗要求速度快,所以只採用了簡單的和校驗,為什麼採用反碼和而不是補碼和呢?
i)反碼和的溢位有後效性(蔓延性)
反碼和將高位溢位加到低位,導致這個溢位會對後面操作有永久影響,有後效性;而補碼和直接將高位和溢位,導致這個溢位對後面的操作再無影響,因此無後效性
ii)反碼校驗無需考慮位元組序
正因為反碼和的溢位有後效性,導致大端位元組序(big-endian)和小端位元組序(little-endian)對同一資料序列(如兩個16位元的序列)產生的校驗和也只是位元組序相反,而補碼和因為將溢位丟掉了,不同位元組序之間的校驗大不相同且沒什麼聯絡。
基於以上的理由,校驗和運算既可選擇在資料被轉換成網路位元組序前,也可選擇在之後。(這其實可以看作是負負得正,計算校驗和與位元組序有關,然後寫校驗和字段與位元組序有關,然後直接計算校驗和再寫校驗和字段則與位元組序無關了~~)
四、 參考文章
關於ip校驗和的
關於網路校驗和的
關於ip校驗和的
,關於補碼和反碼的
IP校驗和詳解
原文見my blog url align center color magenta font 宋體 size 15pt ip size font font 宋體 size 15pt 校驗和詳解 size font color align align left font 宋體 size 14pt 一 ...
IP頭校驗和
這裡要說的是首部校驗和字段。在傳送資料時,為了計算數ip據報的校驗和。應該按如下步驟 1 把ip資料報的首部都置為0,包括校驗和字段。2 把首部看成以16位為單位的數字組成,依次進行二進位制反碼求和。3 把得到的結果存入校驗和字段中。在接收資料時,計算資料報的校驗和相對簡單,按如下步驟 1 把首部看...
IP包的校驗和
ip頭結構 ipv4首部一般是20位元組長。在乙太網幀中,ipv4包首部緊跟著乙太網幀首部,同時乙太網幀首部中的協議型別值設定為0800 16 ipv4提供不同,大部分是很少用的選項,使得ipv4包首部最長可擴充套件到60位元組 總是4個位元組4個位元組的擴充套件 04 8121619 2431 版...