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