我需要按http://www.faqs.org/rfcs/rfc1071.html。
中的描述计算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 :(得分: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
答案 1 :(得分:6)
这里有两个问题。
首先,对struct.unpack_from
的调用仅从缓冲区中解包4个16位值(即8个字节)。如果要解压缩整个标头,则需要执行struct.unpack_from("!nH")
之类的操作,其中n
是要解压缩的短路数。您可以使用struct.unpack_from("!%dH"%(len(data)/2), data)
生成相应的格式字符串,假设data
只包含IP标头。
其次,一旦你这样做,你会发现校验和现在可以达到0.这对于已经设置了校验和的数据包是正确的结果,就像这个一样。 (您突出显示了上面数据包中的A2
和C4
字节。)要从头开始计算数据包的正确校验和,您需要将校验和字节设置为0.(请参阅步骤2的开头)在RFC1071中:“要生成校验和,校验和字段本身将被清除”。)