【问题标题】:calculate IP checksum in python在python中计算IP校验和
【发布时间】:2015-10-08 19:39:16
【问题描述】:

我需要按照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...

谁发现了错误?

已编辑以使错误更清晰 *第二次修改*

【问题讨论】:

  • Python 说:NameError: global name 'a' is not defined。你是说ip_header_sum = ~ip_header_sum & 0xFFFF 吗?
  • 是的,抱歉。现已更正。

标签: python network-protocols checksum


【解决方案1】:

您可以直接使用来自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

【讨论】:

  • 也不起作用。它还给出了结果 0x6524。我相信错误不在于计算,而在于拆包。但是校验和是从包的前 96 位计算出来的,不是吗?
  • 经过编辑以证明它确实有效,提供 zer0 的校验和结果。
【解决方案2】:

这里有两个问题。

首先,您对 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。(请参阅 RFC1071 中步骤 2 的开头:“要生成校验和,校验和字段本身会被清除”。)

【讨论】:

  • 您在上面的数据包中突出显示了 ac 和 c4 字节 - 我不认为 Simon 故意突出显示示例数据包的任何字节,StackOverflow 引擎做了,认为这是一些代码
  • 数据参数包含整个数据包。另外我不解压缩校验和,因此它应该给出校验和(但可能是字节交换)
  • 我已经完成了 nickm 所说的操作,但这仍然不起作用,请参阅更新后的问题
猜你喜欢
  • 2015-12-21
  • 2018-10-23
  • 2012-09-03
  • 1970-01-01
  • 2015-01-02
  • 2021-04-05
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多