checksum udp calculation python

2019-01-18 07:35发布

I'd like to calculate the checksum of an UDP header packet I want to send:

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"""

so I need to join this utf-16 (not a problem) and calculate the checksum of this specific packet. How can I do that?

Thanks!

EDIT: Yes it's an IPv6 header for an ICMPv6 packet, anyways what I would like to know is the formula, and how it works.

I'll give another example with an ICMP ping echo (v4) packet:

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"""

Thanks.

2条回答
Viruses.
2楼-- · 2019-01-18 07:58

There is a solid checksum function that correctly deals with endianness problems in Scapy (http://www.secdev.org/projects/scapy, GPLv2).

In Python 2.7, scapy's 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

This is correct for any protocol which uses the IP header checksum (IP, TCP, UDP, ICMP). However, UDP also has the special case that a checksum calculated as 0x0000 should be transmitted as 0xffff. The above function does not account for that, so for UDP you would have to handle that special case.

查看更多
Evening l夕情丶
3楼-- · 2019-01-18 08:06

This doesn't look like a UDP packet to me. It looks like an IPv6 header for an ICMPv6 packet, but the actual payload of the packet is missing.

IPv6 headers do not contain a checksum.

For ICMP, the checksum is "the 16-bit one's complement of the one's complement sum of the ICMP message starting with the Type field." One's complement arithmetic involves special treatment of the carry bit.

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

In order to calculate the right checksum, of course you have to start with the right msg, which means at least zeroing out the checksum field first and may also require adding "virtual headers", depending on the protocols you're using.

查看更多
登录 后发表回答