【问题标题】:Checksum calculation for ICMPv6 in python校验和 udp 计算 python
【发布时间】:2010-12-18 13:59:09
【问题描述】:

我想计算我要发送的 UDP 标头数据包的校验和:

packetosend = """60 00 00 00 00 24 3a 40 20 02 c0 a8 01 50 00 01 00 00 
00 00 00 00 09 38 20 02 c0 a8 01 50 00 01 00 00 00 00 00 00 09 6f"""

所以我需要加入这个 utf-16(不是问题)并计算 这个 特定数据包的校验和。我该怎么做?

谢谢!

编辑:是的,它是 ICMPv6 数据包的 IPv6 标头,无论如何我想知道的是公式,以及它是如何工作的。

我再举一个 ICMP ping echo (v4) 数据包的例子:

packet = """
08 00 d1 15 76 0c 00 07 bf d3 55 4a ad b5 03 00   // "d1 15" is the packet checksum 
08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37"""

谢谢。

【问题讨论】:

  • 当您查看hashlib 的文档时,您看到了什么?

标签: python networking checksum packet


【解决方案1】:

在我看来,这不像是 UDP 数据包。它看起来像 ICMPv6 数据包的 IPv6 标头,但缺少数据包的实际负载。

IPv6 标头do not contain a checksum

对于ICMP,校验​​和是“以类型字段开头的 ICMP 消息的反码和的 16 位反码”。 One's complement arithmetic 涉及进位的特殊处理。

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

为了计算正确的校验和,当然您必须从正确的msg 开始,这意味着至少首先将校验和字段清零,并且可能还需要添加“虚拟标头”,具体取决于您的协议正在使用。

【讨论】:

  • 我想知道如何将函数校验和中的 w 行更改为 w = (ord(msg[i])
  • @Jason,你的函数校验和需要什么输入类型?
  • 请注意,此校验和函数假定输入“msg”参数的长度是偶数长度。奇数长度输入发生异常。对此的惯用解决方案是在校验和计算期间使用填充字节,该填充字节不作为数据包的一部分传输。 (例如,在校验和函数中,检查 msg 是否为奇数长度,如果是,则将 msg 重新分配给:msg += "\x00"。)
【解决方案2】:

有一个可靠的校验和函数可以正确处理 Scapy 中的字节顺序问题(http://www.secdev.org/projects/scapy,GPLv2)。

在 Python 2.7 中,scapy 的 utils.py:

if struct.pack("H",1) == "\x00\x01": # big endian
    def checksum(pkt):
        if len(pkt) % 2 == 1:
            pkt += "\0"
        s = sum(array.array("H", pkt))
        s = (s >> 16) + (s & 0xffff)
        s += s >> 16
        s = ~s
        return s & 0xffff
else:
    def checksum(pkt):
        if len(pkt) % 2 == 1:
            pkt += "\0"
        s = sum(array.array("H", pkt))
        s = (s >> 16) + (s & 0xffff)
        s += s >> 16
        s = ~s
        return (((s>>8)&0xff)|s<<8) & 0xffff

这对于任何使用 IP 标头校验和(IP、TCP、UDP、ICMP)的协议都是正确的。但是,UDP 也有特殊情况,计算为 0x0000 的校验和应作为 0xffff 传输。上述函数没有考虑到这一点,因此对于 UDP,您必须处理这种特殊情况。

【讨论】:

    猜你喜欢
    • 2010-12-01
    • 2014-08-16
    • 1970-01-01
    • 2015-08-31
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多