DNS-Paket in Python lesen
Diese Frage wurde bereits gestellt, aber die Frage wurde nie vollständig beantwortet und stammt aus dem Jahr 2013. Ich verwende Python-Sockets, um DNS-Pakete zu beobachten. Sie sehen folgendermaßen aus:
b'\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'
Bei der Untersuchung der Grundlagen von DNS-Paketen stellte ich fest, dass sie wie folgt strukturiert sind:
QR | OpCode | AA | TC | RD | RA | Z | AD | CD | RCODE
Ich habe das Paket dann in ASCII dekodiert:
>> 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
Dies gibt nur eine einzelne Zeichenfolge mit dem Namen der Adresse zurück und keine anderen Informationen wie oben angegeben. Wo sind die restlichen Daten wie QR und OpCode? Dekodiere ich es falsch?
Um klar zu sein, ich möchte keine externe Bibliothek verwenden und mein Ziel ist es zu verstehen, wie DNS-Pakete strukturiert sind und wie sie dekodiert werden. Mir sind Bibliotheken wie dnslib
und bekannt scapy
.
Antworten
Ich bin kein Socket-Experte. Aus der Referenz - Der DNS-Header besteht aus Bits, nicht aus Bytes. Sie müssen ihn also als Bits analysieren. Verwenden Sie Bytes und Maskenbits. Siehe Beispiel unten. Es ist nicht sicher, was der Inhalt des Headers hdr [12:] ist?
Hier ist ein Beispielcode, der auf der obigen Spezifikation basiert:
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)
AUSGABE:
DNS PACKET-Wörterbuch {'ID': 257, 'QR': False, 'Opcode': 0, 'AA': False, 'TC': False, 'RD': False, 'RA': False, 'Z': Falsch, 'AD': Falsch, 'CD': Falsch, 'RCode': Falsch, 'QDCOUNT': 0, 'ANCOUNT': 0, 'NSCOUNT': 0, 'ARCOUNT': 3, 'QTYPE': 1, 'QCLASS': 0, 'QNAME': 'www.googletagmanager.com'}
Pyhon-Bit-Manipulation
Beziehen auf
- https://wiki.python.org/moin/BitManipulation
- http://www.java2s.com/Tutorials/Python/Data_Types/How_to_create_integer_in_Python_octal_binary_hexadecimal_and_long_integer.htm
Ein Byte ( b'xxxx'
) steht für 4 Bytes. Jedes Byte besteht aus 8 Bits
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)
In Python konvertiert das Format int ('00000111', 2) ein Array von Strings ['0' / '1'] mit Modulo 2 (Bits). Dies gibt den Wert 7 modulo 10 zurück.
Referenz-DNS-Header: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm

