Python'da DNS paketini okuma

Nov 29 2020

Bu soru daha önce sorulmuştu, ancak soru hiçbir zaman tam olarak ele alınmadı ve 2013'ten itibaren. DNS paketlerini gözlemlemek için python soketleri kullanıyorum, öyle görünüyorlar:

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

DNS paketlerinin temellerini araştırdıktan sonra, şu şekilde yapılandırıldıklarını buldum:

QR | İşlem Kodu | AA | TC | RD | RA | Z | AD | CD | RCODE

Daha sonra paketi ASCII olarak çözdüm:

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

Bu yalnızca adresin adını içeren tek bir dize döndürür ve yukarıda belirtilen diğer bilgileri döndürmez. QR ve İşlem Kodu gibi verilerin geri kalanı nerede? Yanlış mı çözüyorum?

Açık olmak gerekirse, harici bir kitaplık kullanmak istemiyorum ve amacım DNS paketlerinin nasıl yapılandırıldığını ve bunların nasıl çözüleceğini anlamak; Ben gibi kütüphanelerin farkındayım dnslibve scapy.

Yanıtlar

2 frankr6591 Nov 29 2020 at 21:50

Soket uzmanı değilim. Referanstan - DNS başlığı bayt değil bitlerden oluşur ... bu nedenle onu bit olarak ayrıştırmanız gerekir. Bayt ve maske bitlerini kullanın. Aşağıdaki örneğe bakın. Hdr [12:] başlığının hangi içeriğinin olduğundan emin değil misiniz?

İşte yukarıdaki spesifikasyona dayalı bazı örnek kodlar:

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)

ÇIKTI:

DNS PAKET sözlüğü {'ID': 257, 'QR': False, 'Opcode': 0, 'AA': False, 'TC': False, 'RD': False, 'RA': False, 'Z': False, 'AD': False, 'CD': False, 'RCode': False, 'QDCOUNT': 0, 'ANCOUNT': 0, 'NSCOUNT': 0, 'ARCOUNT': 3, 'QTYPE': 1, 'QCLASS': 0, 'QNAME': 'www.googletagmanager.com'}

Pyhon Bit Manipülasyonu

Bakın

  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

Bir bayt ( b'xxxx') 4 baytı temsil eder. Her bayt 8 bitten oluşur

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)

Python'da int ('00000111', 2) biçimi, modulo 2 (bit) kullanarak bir dizi ['0' / '1'] dönüştürür. Bu, 7 modulo 10 değerini döndürür.

Referans DNS Başlığı: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm