Membaca paket DNS dengan python

Nov 29 2020

Pertanyaan ini telah ditanyakan sebelumnya tetapi pertanyaan itu tidak pernah dijawab sepenuhnya, dan dari tahun 2013. Saya menggunakan soket python untuk mengamati paket DNS, mereka tampak seperti ini:

b'\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'

Setelah meneliti dasar-dasar paket DNS, saya menemukan mereka terstruktur seperti ini:

QR | OpCode | AA | TC | RD | RA | Z | AD | CD | RCODE

Saya kemudian mendekodekan paket ke ASCII:

>> str = b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'
>> print(str.decode("ascii"))
wwwgoogletagmanagercom

Ini hanya mengembalikan satu string dengan nama alamat, dan bukan info lain seperti yang ditentukan di atas. Di mana data lainnya, seperti QR dan OpCode? Apakah saya salah mendekodekannya?

Untuk lebih jelasnya, saya tidak ingin menggunakan pustaka eksternal dan tujuan saya adalah untuk memahami bagaimana paket DNS disusun dan bagaimana memecahkan kodenya; Saya mengetahui perpustakaan seperti dnslibdan scapy.

Jawaban

2 frankr6591 Nov 29 2020 at 21:50

Saya bukan ahli soket. Dari referensi - header DNS terdiri dari bit, bukan byte ... jadi Anda perlu menguraikannya sebagai bit. Gunakan byte dan bit mask. Lihat contoh di bawah. Tidak yakin apa isi dari header hdr [12:] itu?

Berikut beberapa contoh kode berdasarkan spesifikasi di atas:

def DNStoDict(hdr):
    '''
    Parse QNAME by using length (byte) +data sequence -- final length=0 signifies end of QNAME
    Refer to https://stackoverflow.com/questions/34841206/why-is-the-content-of-qname-field-not-the-original-domain-in-a-dns-message

    1) DNS knows nothing of URLs. DNS is older than the concept of a URL.

    2) Because that's how DNS's wire format works. What you see is the 
       domain name www.mydomain.com, encoded in the DNS binary format. 
       Length+data is a very common way of storing strings in general.
    '''

        # Build DNS dictionary of values... include QNAME
    l = len(hdr)
    argSize = hdr[10]*256+hdr[11]
    dnsDict = dict(ID     = hdr[0]*256+hdr[1],
                   QR     = bool(hdr[2] & int('10000000', 2)),
                   Opcode =     (hdr[2] & int('01111000', 2))>>3,
                   AA     = bool(hdr[2] & int('00000100', 2)),
                   TC     = bool(hdr[2] & int('00000010', 2)),
                   RD     = bool(hdr[2] & int('00000001', 2)),
                   RA     = bool(hdr[3] & int('10000000', 2)),
                   Z      = bool(hdr[3] & int('01000000', 2)),
                   AD     = bool(hdr[3] & int('00100000', 2)),
                   CD     = bool(hdr[3] & int('00010000', 2)),
                   RCode  = bool(hdr[3] & int('00001111', 2)),
                   QDCOUNT = hdr[4]*256+hdr[5],
                   ANCOUNT = hdr[6]*256+hdr[7],
                   NSCOUNT = hdr[8]*256+hdr[9],
                   ARCOUNT = argSize,
                   QTYPE   = hdr[l-4]*256+hdr[l-3],
                   QCLASS   = hdr[l-2]*256+hdr[l-2])

    # Parse QNAME
    n = 12
    mx = len(hdr)
    qname = ''

    while n < mx:
        try:
            qname += hdr[n:n+argSize].decode() + '.'

            n += argSize
            argSize = int(hdr[n])
            n += 1
            if argSize == 0 : 
                break
        except Exception as err:
            print("Parse Error", err, n, qname)
            break
    dnsDict['QNAME'] = qname[:-1]
    return dnsDict

# Sample DNS Packet Data 
hdr = b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'


# Parse out the QNAME
dnsDict = DNStoDict(hdr)


print("\n DNS PACKET dictionary")
print(dnsDict)

KELUARAN:

Kamus PACKET DNS {'ID': 257, 'QR': False, 'Opcode': 0, 'AA': False, 'TC': False, 'RD': False, 'RA': False, 'Z': Salah, 'AD': False, 'CD': False, 'RCode': False, 'QDCOUNT': 0, 'ANCOUNT': 0, 'NSCOUNT': 0, 'ARCOUNT': 3, 'QTYPE': 1, 'QCLASS': 0, 'QNAME': 'www.googletagmanager.com'}

Manipulasi Bit Pyhon

Mengacu pada

  1. https://wiki.python.org/moin/BitManipulation
  2. http://www.java2s.com/Tutorials/Python/Data_Types/How_to_create_integer_in_Python_octal_binary_hexadecimal_and_long_integer.htm

Sebuah byte ( b'xxxx') mewakili 4 byte. Setiap byte terdiri dari 8 bit

0000 0000 - 0 0000 0001 - 1 0000 0010 - 2 0000 0100 - 4 0000 1000 - 8 0001 0000 - 16 0010 0000 - 32 0100 0000 - 64 1000 0000 - 128 1111 1111 - 255 (128 + 64 + 32 + 16 + 8 + 4 + 2 + 1)

Dalam python, format int ('00000111', 2) mengubah array string ['0' / '1'] menggunakan modulo 2 (bits). Ini mengembalikan nilai 7 modulo 10.

Referensi Header DNS: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm