[back]
Python Raw Packet
modified: 2015-03-22 04:22:15

Been working on some a project and needed to craft raw packets in Python. As an example to generate a simple limited functionality DNS query. The source MAC address and your gateway or target ETH device has to be manually keyed although you could easily grab that from somewhere:

    data = craftDNSQuery(
        srcmac = [0xec, 0x55, 0xf9, 0x7a, 0x54, 0x70],
        dstmac = [0xa0, 0x21, 0xb7, 0xb2, 0x28, 0xe9],
        srcaddr = craftIP4Address(192, 168, 1, 114),
        dstaddr = craftIP4Address(8, 8, 8, 8),
        srcport = 400, dstport = 53, tranid = 0x1234
    )

The library module here:

    #!/usr/bin/python3
    import socket
    import struct

    def craftETH2(data, dst = [0, 0, 0, 0, 0, 0], src = [0, 0, 0, 0, 0, 0], proto = 0x0800):
        hdr = struct.pack(
            '!BBBBBBBBBBBBH',
            dst[0], dst[1], dst[2],
            dst[3], dst[4], dst[5],
            src[0], src[1], src[2],
            src[3], src[4], src[5],
            proto
        )
    
        return hdr + data

    def craftUDP(data, srcport = 0, dstport = 0):
        chksum = 0
        hdr = struct.pack(
            '!HHHH',
            srcport,
            dstport,
            len(data) + 2 * 4,
            chksum
        )
        return bytes(list(hdr) + list(data))

    def craftIP4(data, src = 0, frag = 0, dst = 0, iden = 0, proto = 17, ttl = 255, version = 4, flags = 0, diffServices = 0):
        hdrlen = 5
        totLen = hdrlen * 4 + len(data)
        checksum = 0x0
        pkt = struct.pack(
            '!BBHHBBBBHII',
            (version << 4) | hdrlen,
            diffServices,
            totLen,
            iden,
            flags,
            frag,
            ttl,
            proto,
            checksum,
            src,
            dst
        )
    
        pkt = list(pkt)

        x = 0
        s = 0
        while x < 10:
            v = pkt[x * 2 + 0] | pkt[x * 2 + 1] << 8
            s = s + v
            x = x + 1
    
        #print(struct.pack('H', ~s))

        mask = (1 << s.bit_length()) - 1
        s = s ^ mask
        s = s - 1
    
        print('sum:%s' % hex(s))

        pkt[11] = (s >> 8) & 0xff
        pkt[10] = s & 0xff
    
        return bytes(pkt + list(data))

    def craftDNSQuery(
        srcmac = None, dstmac = None,
        srcport = 0, dstport = 0,
        srcaddr = 0, dstaddr = 0,
        tranid = 0,
        host = 'www.google.com'):

        hdr = struct.pack(
            '!HHHHHH',
            tranid,
            0x0100,
            1, 0, 0, 0
        )

        l = host.split('.')
        data = []
        for e in l:
            data = data + [len(e)]
            data = data + list(bytes(e, 'utf8'))
    
        data = bytes(data + [0, 0, 1, 0, 1])
        data = hdr + data

        data = craftUDP(
            data,
            srcport = srcport,
            dstport = dstport
        )
        data = craftIP4(
            data,
            proto = 17,
            src = srcaddr,
            dst = dstaddr
        )
        data = craftETH2(
            data,
            src = srcmac,
            dst = dstmac
        )

    
        return data

    def craftDNSReply(srcport = 0, dstport = 0, srcaddr = 0, dstaddr = 0, tranid = 0, host = 0, target = 0):
        return None

    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
    sock.bind(('eth0', 0))

    #data = craftUDP(bytes([2, 3]), srcport = 1, dstport = 2)
    #data = craftIP4(data, proto = 17, src = 0x12121212, dst = 0x12345678)
    #data = craftETH2(data, dst = [1,2,3,4,5,6])
    #sock.send(data)

    def craftIP4Address(a, b, c, d):
        return a << 24 | b << 16 | c << 8 | d

    data = craftDNSQuery(
        srcmac = [0xec, 0x55, 0xf9, 0x7a, 0x54, 0x70],
        dstmac = [0xa0, 0x21, 0xb7, 0xb2, 0x28, 0xe9],
        srcaddr = craftIP4Address(192, 168, 1, 114),
        dstaddr = craftIP4Address(8, 8, 8, 8),
        srcport = 400, dstport = 53, tranid = 0x1234
    )

    print(data)
    e = sock.send(data)