Lire le paquet DNS en python
Cette question avait déjà été posée mais la question n'a jamais été entièrement traitée et date de 2013. J'utilise des sockets python pour observer les paquets DNS, ils se présentent comme suit:
b'\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'
En recherchant les principes fondamentaux des paquets DNS, j'ai trouvé qu'ils sont structurés comme suit:
QR | OpCode | AA | TC | RD | RA | Z | AD | CD | RCODE
J'ai ensuite décodé le paquet en 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
Cela ne renvoie qu'une seule chaîne avec le nom de l'adresse, et pas d'autres informations comme spécifié ci-dessus. Où est le reste des données, comme le QR et l'OpCode? Suis-je en train de le décoder incorrectement?
Pour être clair, je ne souhaite pas utiliser de bibliothèque externe et mon objectif est de comprendre comment les paquets DNS sont structurés et comment les décoder; Je connais des bibliothèques telles que dnslib
et scapy
.
Réponses
Je ne suis pas un expert en socket. From reference - L'en-tête DNS est composé de bits et non d'octets ... vous devez donc l'analyser sous forme de bits. Utilisez des octets et des bits de masque. Voir l'exemple ci-dessous. Il ne sait pas quel est le contenu de l'en-tête hdr [12:]?
Voici un exemple de code basé sur les spécifications ci-dessus:
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)
PRODUCTION:
Dictionnaire DNS PACKET {'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'}
Manipulation de bits Pyhon
Faire référence à
- 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
Un octet ( b'xxxx'
) représente 4 octets. Chaque octet est composé de 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)
En python, le format int ('00000111', 2) est de convertir un tableau de chaînes ['0' / '1'] en utilisant modulo 2 (bits). Cela renvoie la valeur 7 modulo 10.
En-tête DNS de référence: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm

