checksum是為了保證 header 或 data 不被破壞而發展出來的機制,IP層有IP層的checksum,TCP有TCP的checksum,計算方式都大同小異,checksum的演算法如下,以IP層為例
def getIPChecksum(data):
for index in range(0,len(data),2):
word = (data[index] << 8) + (data[index+1])
sum = sum + word
sum = (sum >> 16) + (sum & 0xffff);
sum = ~sum & 0xffff
return sum
然後下面是打包header的方法
response_ipheader = struct.pack('!BBHHHBBH4s4s', IHL_VERSION, TYPE_OF_SERVICE, total_len, pktID, FRAGMENT_STATUS, TIME_TO_LIVE, PROTOCOL, 0, dest_IP,src_IP
) # 一開始,checksum的位置置0
check_sum_of_ip = getIPChecksum(response_ipheader) # 把header加密成checksum
response_ipheader = struct.pack('!BBHHHBBH4s4s', IHL_VERSION, TYPE_OF_SERVICE, total_len, pktID, FRAGMENT_STATUS, TIME_TO_LIVE, PROTOCOL, check_sum_of_ip, dest_IP,src_IP) # 再把算好的checksum包進去header
大功告成!
基本上Checkusm採取一種非常弱的16-bit check sum演算法,這種checksum算法能檢出一些簡單的錯誤,而對某些錯誤無能為力,由於是簡單的加法,遇到“和”不變的情況就無法檢查出錯誤(比如交換兩個16-bit整數,加法滿足交換律,結果不變),或是換個角度想,16bit整數也不過是65536,可見如果header或data變了還是同個checksum的機率很高。
由於發送封包往往會經過多級路由,路由器可能出現硬件故障,比方說它的記憶體故障或是偶爾的錯誤導致收发IP封包出現多bit的反轉或雙字節交換,這個反轉如果发生在data段,那麽無法用鏈路層、網絡層、傳輸層的check sum查出來,只能通過應用層的check sum來檢測,所以在網路上下載大文件的時候,經常看到網站也提供md5校驗。
系列的成果將會放在這:https://github.com/kaichiachen/pytcpdump
文章配合著程式碼有助於學習 :)