


【摘 要】 信息時代,龐大的數據集合中,信息交互的出錯在所難免。對于差錯處理,網際校驗和算法的應用具有里程碑式的意義。算法利用網絡數據使用二進制代碼的特點,通過對信息串進行反碼相關運算,“放大”通信兩端數據出現的差異,較大程度地減少了出錯概率。這一算法的思想如今已經被應用在IP、ICMP、 UDP和TCP等諸多報文的檢錯運算中。
本文將對網際校驗的基本思想和使用情況做出簡要論述,并使用python編制一個具有識別報文類型和驗算校驗和功能的代碼示例。
技術上,在抓取報文時使用了網絡抓包軟件WireShark;識別報文類型時,依賴了python強大的字符串處理能力;驗算校驗和算法以二進制反碼運算為基礎。
【關鍵詞】 網際校驗和 IP UDP TCP ICMP 二進制 反碼運算 互聯網
一、網際校驗和算法
(一)算法概述
一般的網際校驗和算法過程分為兩步。
第一步是,對報文分段進行二進制反碼加法運算。對于需要檢測的報文部分,在發送方,先將被檢測報文的對應校驗和字段置為全0,繼而把該部分內容以16位為一個單位分組,再將這些分組分別進行二進制反碼加法運算,將得到的結果存入到對應校驗和字段,覆蓋掉全0。發送方將這樣的報文發送出去。
第二步,在接收方,將收到的報文部分以和第一步中同樣方式分段進行二進制反碼的加法運算。這個時候,得到結果要么是全0要么是全1。為什么呢?
我們以IP數據報為例,假設IP數據報首部只有32位也就是4個字節,經16位的劃分,可分為兩個16位的字序列,我們暫稱其為A和B。(此時未填入數據的IP數據報首部校驗和字段的值為0)則根據上述算法,此時首部校驗和則為 A+B+0 = A+B,結果再求反。將A+B記為C,那則首部校驗和就是 非C 。當報文傳送到接收方,接收方再按照16位子序列去劃分報文首部,此時首部校驗和字段是 非C,則需要計算的是A+B+ 非C = A+B+ 非(A+B) = 1(數字邏輯運算)。也就是說,只要IP數據報首部未變,到此運算結果必為1。(若再求反,則結果為就為0。)
(二)不同協議的報文運算區別
網際校驗和算法在不同的協議實現的時候,是有使用差別的。
主要分為兩方面:1.檢驗字段范圍;2.正確的驗證結果。
對于需要檢驗的字段范圍,IP和ICMP報文不需要附加額外的字段,其中IP只需要檢驗IP數據報的首部字段,ICMP則需要同時檢測首部和數據部分;TCP報文段和UDP用戶數據報檢驗范圍都是首部加上數據部分,但是二者在進行校驗和運算的時候,還需要在報文的首部前加上額外的12字節的被稱為“偽首部”的字段,作為參與運算的一部分。但是偽首部不作為信息向上遞交。
對于正確的驗證結果,其中IP和ICMP對最終的正確結果要求是全0,TCP和UDP對于最終正確結果的要求是全1。其實計算的原理都是一樣的,正常的經過一輪網際校驗和的運算后結果為全1,不過在TCP和ICMP的檢驗過程中,會將結果再次求反,于是獲得全0。
二、算法實現
(一)獲取報文
使用抓包工具WireShark,在上網時獲取到相應的MAC幀數據,并以此為基礎向內解析出所含的IP數據報、TCP報文段或者UDP報文段。。
限于篇幅,測試數據在此不詳細列出,請感興趣的讀者自行嘗試抓包。
(二)區分報文的方法
報文的格式與包含關系請讀者先了解有關資料,這里限于篇幅不再展示。
在報文都是2進制表示的情況下,若想從MAC幀中提取完整的IP數據報,取得MAC幀中(從0開始的)第14×8位往后的數據即可。在IP中,首先判斷第72~79(“協議”字段)位的數據,若是6,則表示TCP,若是17,則表示UDP,否則表示ICMP。
對于首部檢驗和字段,IP在第80~95位,ICMP在第16~31位置,TCP在第128~143位(不含偽首部),UDP在第48~63位(不含偽首部)。
(三)算法思路
1.獲取用戶按指定格式輸入的報文信息;
2.根據1.2中的區分報文原則,將IP數據報整體劃分出來;
3.對IP首部進行校驗和計算,有誤則提示錯誤,無誤則繼續提取協議字段,判斷其值;
1)若為6,則是TCP,
提取TCP報文段整體,進行校驗和計算,有誤則提示錯誤,無誤則完成校驗;
2)若為17,則為UDP,
提取UDP報文段整體,進行校驗和計算,有誤則提示錯誤,無誤則完成校驗;
3)不是6或17,則為ICMP,
提取ICMP報文段整體,進行校驗和計算,有誤則提示錯誤,無誤則完成校驗。
使用Python語言完成了本次編碼。
(四)關鍵代碼示例
1.報文分組
"""
對指定的字符串進行4位一組分組,每組二進制加法運算
"""
def get_grouped_sum(s):
s2 = s
length = len(s2)
counter = int(length / 16)
ls = []
for i in range(0, counter):
ls.append(bin(int(s2[0: 16], 2))[2:])
s2 = s2[16:]
return get_bin_sum(ls)
2.對分組進行二進制反碼加法
'''
取得反碼求和運算之結果
'''
def get_bin_sum(ls):
bin_sum = 0
for v in ls:
bin_sum = bin_sum + int(v, 2)
if len((bin(bin_sum))[2:]) > 16:
result = bin(bin_sum)[3:]
bin_sum = int(result, 2) + 1
return get_inverse(bin(bin_sum)[2:])
3.對結果進行求反
'''
在字符串中將原碼“笨拙”地替換為反碼
'''
def get_inverse(s):
inverse = ''
d = {'0': '1', '1': '0'}
for e in s:
inverse += d[e]
return bin(int(inverse, 2))[2:].zfill(16)
【參考文獻】
[1] 施展. 新型互聯網傳輸協議的差錯控制設計與協議一致性測試[D]. 北京:北京交通大學,2018
[2] 謝希仁. 計算機網絡(第七版)[M].北京:電子工業出版社,2017:96,128,209-210,216-217
[3] Zed A. Shaw. “笨方法”學Python3 [M].北京:中國郵電出版社,2018:98
作者簡介:劉楊(1999——)男,漢族,河南信陽人,單位:河南大學計算機與信息工程學院,本科,軟件工程專業,軟件工程: