關於TCP校驗和的一些實驗體會

一、校驗算法介紹

對於IP數據包來說,校驗和用於檢驗首部的有效性和完整性,首部發生變化時。如減少TTL、減少或改變選項、發生分片等,都要重新計算校驗和。過程是先把首部檢驗和字段置爲0,然後把首部分成一塊16bit的數據來處理,計算每個16bit的整數的反碼,再求他們的和,最後計算出結果的反碼。方法二可以直接求每個16bit的和,最後在把高16bit的數據加到低16bit位中(最後高16bit是全爲0的),在求反碼。

例如求和之後結果爲0x7ffff,高位加到低位 0x7+0xffff = 0x10006 ,高位還有數據,繼續高位加到低位 0x6 + 0x1 = 0x7,之後求反碼 0xffff - 0x7 = fff8。fff8就爲校驗和。

TCP校驗和算法是用TCP僞首部+TCP首部+數據的16bit之和來計算,而且裏面的字段1個字節以上的必須要要轉換成網絡字節序。假如數據是奇數位的話,那最後8bit的數據就要用0填充爲16bit的數據,如0x12 0x34 0x56,則變成0x12+0x34+0x5600。

校驗和就簡單的說明一下,算法網上隨便都可以搜到,我想要說的重點不是這個。

這裏寫圖片描述

二、校驗和與字節序的問題

在剛開始瞭解校驗和的時候,覺得網上提供的資料雖然已經到位,但是不夠全面,因爲總覺得有一些繁雜的東西沒有梳理清楚。這一節要說的就是**字節序**的問題。學習網絡編程,字節序就是其中的一個麻煩的絆腳石,即使你前一段時間想通了它,但是不過多久就會忘了。

問1:校驗和計算爲什麼都用主機字節序?
主機在校驗過程中就按主機字節序來讀取數據,因爲校驗的過程是對稱的,與大小尾端無關。
例如有以下數據0x12,0x34
校驗和爲EDCB,如果我反過來讀取數據,結果也是一樣的。0x3412+CBED = FFFF。

問2:檢驗和爲什麼不需要字節序轉換?
試想一下,數據包流向一個環回地址,則主機接收自己發出的數據包,則數據包的校驗和同樣由本機處理。計算的數據如果進行了字節序轉換,那和原來校驗和取反之前的結果相加就不爲FFFF了。
例如有以下數據0x12,0x34,0x56,0x78
校驗和 = ~(0x12 + 0x34 + 0x56 + 0x78)= 0x9753
就有 0x9753 + 0x12 + 0x34 + 0x56 + 0x78 = FFFF
如果把校驗和字節序轉換,那上述結構就不會等於FFFF了。

三、校驗和代碼的缺陷

先給出C的代碼。

USHORT checksum(USHORT* buffer, int size)
{
    unsigned long cksum = 0;

    while(size>1)
    {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }
    if(size)
    {
        cksum += *(UCHAR*)buffer;           //問題所在處!!!!!
    }
    cksum = (cksum>>16) + (cksum & 0xffff); //將高16bit與低16bit相加
    cksum += (cksum>>16);                   //將進位到高位的16bit與低16bit 再相加

    return (USHORT)(~cksum);
}

問題就出在如果數據是奇數位的話,讀取數據會不會出錯呢,答案是會出錯的。

因爲之前在瞭解校驗和算法的時候,一直記得奇數位最後的8bit數據一定要填充爲16bit的數據來計算,所以看到代碼在處理奇數位數據的時候用的是UCHAR型,意思爲取一個字節的數據加到和的最低字節。
後來試着從最後一位數據處理的代碼片裏面用UCHAR和USHORT類型輸出數據,發現結果是一樣的。觀察了很久才知道主機是小尾端字節序的。就不禁引出疑問,如果是大尾端的機器,那會不會結果不一樣呢?

有以下數據0x12,0x34,0x56,0x00
小尾端讀取到的數據是 0x3412, 0x56
理論大尾端讀取到的數據是0x1234, 0x5600,實際上是0x1234, 0x00
所以這個算法要修改 cksum += (UCHAR)buffer 爲 cksum += (USHORT)buffer。

但是問題還沒解決,依然存在着緩衝區對數據的影響。
如果上述數據0x56的後面不是0x00的話,而是其他不屬於計算範圍的數據,就會導致取到錯誤的數據。所以緩衝區一定要大於數據長度,並且還要初始化。

同理IP首部的長度32bit爲單位的,計算IP首部不會存在奇數位。

以上是本人的一些看法,若有不足之處,希望各位大牛多加指點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章