2010-10-16 198 views
1

我需要計算IP數據包的校驗和,如http://www.faqs.org/rfcs/rfc1071.html中所述。在Python中計算IP校驗和

我已經下面的代碼:

#!/usr/bin/python 
import struct 

data = "45 00 00 47 73 88 40 00 40 06 a2 c4 83 9f 0e 85 83 9f 0e a1" 

# a test for the checksum calculation 

def _checksum(data): 
    #calculate the header sum 
    ip_header_sum = sum(struct.unpack_from("6H", data)) 
    #add the carry 
    ip_header_sum = (ip_header_sum & 0xFFFF) + (ip_header_sum >> 16 & 0xFFFF) 
    #invert the sum, python does not support inversion (~a is -a + 1) so we have to do 
    #little trick: ~a is the same as 0xFFFF & ~a 
    ip_header_sum = ~ip_header_sum & 0xFFFF 

    return ip_header_sum #should return 0 if correct 

data = data.split() 
data = map(lambda x: int(x,16), data) 
data = struct.pack("%dB" % len(data), *data) 

print " ".join(map(lambda x: "0x%02x" % ord(x), data)) 
print "Checksum: 0x%04x" % _checksum(data) 

它與我所使用Wireshark捕獲和一個包,必須具有正確的校驗和,因此應計算爲0

不幸的是,結果是0x6524。 有趣的是,對於每個正確的數據包,結果始終爲0x6524 ...

誰發現錯誤?

編輯,以使誤差更清晰 * *編輯

+0

Python的說:'NameError:全局名稱 '一個' 不defined'。你的意思是'ip_header_sum =〜ip_header_sum&0xFFFF'? – Seth 2010-10-16 17:51:02

+0

對不起。現在已經糾正了。 – Simon 2010-10-16 18:53:00

回答

8

您可以直接使用checksum udp calculation python的解決方案,這會導致預期的校驗和值爲零。

import struct 

data = "45 00 00 47 73 88 40 00 40 06 a2 c4 83 9f 0e 85 83 9f 0e a1" 

def carry_around_add(a, b): 
    c = a + b 
    return (c & 0xffff) + (c >> 16) 

def checksum(msg): 
    s = 0 
    for i in range(0, len(msg), 2): 
     w = ord(msg[i]) + (ord(msg[i+1]) << 8) 
     s = carry_around_add(s, w) 
    return ~s & 0xffff 

data = data.split() 
data = map(lambda x: int(x,16), data) 
data = struct.pack("%dB" % len(data), *data) 

print ' '.join('%02X' % ord(x) for x in data) 
print "Checksum: 0x%04x" % checksum(data) 

結果:

45 00 00 47 73 88 40 00 40 06 A2 C4 83 9F 0E 85 83 9F 0E A1 
Checksum: 0x0000 
+0

也不起作用。它也給出了結果0x6524。我相信錯誤不在計算中,而是在解包中。但校驗和是從軟件包的前96位計算出來的,不是嗎? – Simon 2010-10-17 17:17:21

+0

爲了證明它確實有效,提供了zer0的校驗和結果。 – 2010-10-18 16:57:33

6

你有兩個問題在這裏第二次。

首先,您撥打struct.unpack_from的電話只打開緩衝區中的4個16位值(即8個字節)。如果你想解開整個標題,你需要做一些類似struct.unpack_from("!nH")的地方,其中n是你想要解包的短褲數量。假設data只包含IP標頭,則可以使用struct.unpack_from("!%dH"%(len(data)/2), data)生成適當的格式字符串。

其次,一旦你這樣做了,你會發現校驗和現在可以達到0.這是一個已經有校驗和的數據包的正確結果,就像這樣。 (您在上面的數據包中突出顯示了A2C4字節。)要從頭開始計算數據包的正確校驗和,需要將校驗和字節設置爲0.(請參閱RFC1071中步驟2的開頭:「生成校驗和,校驗和字段本身被清除「)。

+2

*您突出顯示了上面的數據包中的ac和c4字節* - 我不認爲Simon有意突出顯示了示例數據包的任何字節,StackOverflow引擎的確認爲它是一些代碼 – mykhal 2010-10-16 19:17:24

+0

數據參數包含整個數據包。我也沒有解開校驗和所以它應該給校驗和(但可能是字節交換) – Simon 2010-10-16 20:58:35

+0

我已經做了什麼尼克告訴,但仍然不起作用,看到更新的問題 – Simon 2010-10-17 14:35:20