#!/usr/bin/env python3 # Code copied from /usr/lib/python3/dist-packages/scapy/utils.py import struct import array if struct.pack("H",1) == b"\x00\x01": # big endian def checksum(pkt): if len(pkt) % 2 == 1: pkt += b"\0" s = sum(array.array("H", pkt)) s = (s >> 16) + (s & 0xffff) s += s >> 16 s = ~s return s & 0xffff else: def checksum(pkt): # padding to even length if len(pkt) % 2 == 1: pkt += b"\0" # create array with unsigned shorts, # sum it up -> results in 16 bit uint (?) s = sum(array.array("H", pkt)) print("sum={}".format(s)) # This step is understood # (s & 0xffff) -> mask for 16 bit, truncate rest # (s >> 16) right shift by 16 bits # >>> 2**17 >> 16 # 2 # Basically: # add higher 16 bits to lower 16 bits s = (s >> 16) + (s & 0xffff) # Now we add the remaining possible 16 bits # i.e. above we take bits 0..15 + 16..31 # now we add [0..15 + 16..31] + "32..47" # I assume this is for catching the carry # over bits from the previous calculation s += s >> 16 # according to https://stackoverflow.com/questions/8305199/the-tilde-operator-in-python # ~ is the bitwise complement operator in python # which essentially calculates -x - 1 # 2 complement s = ~s # (s>>8)&0xff) -> filter bits 8..15 # | = bitwise OR # s<<8 : left shift everything in original s # | s<<8: ? # & 0xffff: filter / allow only 16 bits # Seems like the idea is to filter correctly for # 16 bit - unclear why "s & 0xffff" does not do the job return (((s>>8)&0xff)|s<<8) & 0xffff if __name__ == '__main__': import sys pkt = sys.argv[1] pkt_bytes = pkt.encode('utf-8') print(pkt_bytes) print(checksum(pkt_bytes)) ipv4 = "AAAA" ipv6 = "BBAA"