網路資料包效驗和(checksum)的計算
在網路傳送的資料包為了保證傳送正確都含有效驗欄位,IP、arp、tcp等每
個數據段都有自己的效驗和。
效驗的計算並不複雜。把相應資料包段的所有資料看成一個位元組陣列
{a,b,c,d,e},把他們分成16bit一組
{[ab],[cd],[e0]}
計算其和:
[ab]
[cd]
[e0]
--------
[xy]
計算採用迴圈進位,最高位的進位加到最低位,
如果計算出的[xy]所有位都為1(即為1111 1111)則效驗通過。
如果[cd]為效驗和的話,已經填好其他各個位元組,如何計算出[cd]
(checksum)的值呢?我們首先用0填充[cd],然後算出[xy],則正確的[cd]應該為計
算出的[xy]按位求反的結果。這樣才能保證整個資料包段通過效驗。
實際程式中,因為現在的機器都是32位的,所以採用變通的演算法:
Byte-by-byte Normal Swapped
Order Order
Byte 0/1: 00 01 0001 0100
Byte 2/3: f2 03 f203 03f2
Byte 4/5: f4 f5 f4f5 f5f4
Byte 6/7: f6 f7 f6f7 f7f6
--- --- ----- -----
Sum1: 2dc 1f0 2ddf0 1f2dc
dc f0 ddf0 f2dc
Carrys: 1 2 2 1
-- -- ---- ----
Sum2: dd f2 ddf2 f2dd
Final Swap: dd f2 ddf2 ddf2
------------------------------
Byte 0/1/2/3: 0001f203 010003f2 03f20100
Byte 4/5/6/7: f4f5f6f7 f5f4f7f6 f7f6f5f4
-------- -------- --------
Sum1: 0f4f7e8fa 0f6f4fbe8 0fbe8f6f4
Carries: 0 0 0
Top half: f4f7 f6f4 fbe8
Bottom half: e8fa fbe8 f6f4
----- ----- -----
Sum2: 1ddf1 1f2dc 1f2dc
ddf1 f2dc f2dc
Carrys: 1 1 1
---- ---- ----
Sum3: ddf2 f2dd f2dd
Final Swap: ddf2 ddf2 ddf2
可以看到先求32位的checksum,然後將高8位與低八位相加,最終求出的
checksum是相同的。
給出一段C++實現的演算法:
in 6
{
/* Compute Internet Checksum for count bytes
* beginning at location addr.
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* 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);
checksum = ~sum;
}
本文轉自
http://it.icxo.com/htmlnews/2004/07/20/270977.htm