leyendo paquetes DNS en Python

Estoy jugando con sockets de Python y decidí ver si podía implementar un servidor de nombres muy básico (es decir, una tabla de búsqueda para un nombre de dominio para una dirección IP). Así que he configurado mi servidor hasta ahora para simplemente volcar los datos recibidos.

#!/usr/bin/python import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) host = '' port = 53 size = 512 s.bind((host, port)) while True: data, addr = s.recvfrom(size) print repr(data) 

Cuando ejecuto el código anterior y apunto mi DNS a 127.0.0.1 obtengo algo parecido a lo siguiente:

 'Y\x04\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01' 'J\xaa\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x1c\x00\x01' 'Y\x04\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01' 

Supongo que es algo que ver con la estructura del paquete de preguntas del DNS, pero no estoy seguro.

A) ¿Son los personajes de escape anteriores? ¿Una encoding de texto específica? ¿O simplemente los bytes?

B) ¿Cómo puedo interpretar los datos y trabajar con ellos?

EDITAR: Cambiar el socket para tomar en bruto en lugar de datagtwigs da como resultado lo siguiente:

 'E\x00$\x00\xe4\x96\x00\x00@\x01\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\x03\x03X\xb6\x00\x00\x00\x00E\x00V\x00m\x82\x00\x00\xff\x11\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\xf3\xe1\x005\x00B\x00\x00' 

Podrías comenzar con algo como esto:

 #!/usr/bin/env python import pprint import socket import struct def decode_labels(message, offset): labels = [] while True: length, = struct.unpack_from("!B", message, offset) if (length & 0xC0) == 0xC0: pointer, = struct.unpack_from("!H", message, offset) offset += 2 return labels + decode_labels(message, pointer & 0x3FFF), offset if (length & 0xC0) != 0x00: raise StandardError("unknown label encoding") offset += 1 if length == 0: return labels, offset labels.append(*struct.unpack_from("!%ds" % length, message, offset)) offset += length DNS_QUERY_SECTION_FORMAT = struct.Struct("!2H") def decode_question_section(message, offset, qdcount): questions = [] for _ in range(qdcount): qname, offset = decode_labels(message, offset) qtype, qclass = DNS_QUERY_SECTION_FORMAT.unpack_from(message, offset) offset += DNS_QUERY_SECTION_FORMAT.size question = {"domain_name": qname, "query_type": qtype, "query_class": qclass} questions.append(question) return questions, offset DNS_QUERY_MESSAGE_HEADER = struct.Struct("!6H") def decode_dns_message(message): id, misc, qdcount, ancount, nscount, arcount = DNS_QUERY_MESSAGE_HEADER.unpack_from(message) qr = (misc & 0x8000) != 0 opcode = (misc & 0x7800) >> 11 aa = (misc & 0x0400) != 0 tc = (misc & 0x200) != 0 rd = (misc & 0x100) != 0 ra = (misc & 0x80) != 0 z = (misc & 0x70) >> 4 rcode = misc & 0xF offset = DNS_QUERY_MESSAGE_HEADER.size questions, offset = decode_question_section(message, offset, qdcount) result = {"id": id, "is_response": qr, "opcode": opcode, "is_authoritative": aa, "is_truncated": tc, "recursion_desired": rd, "recursion_available": ra, "reserved": z, "response_code": rcode, "question_count": qdcount, "answer_count": ancount, "authority_count": nscount, "additional_count": arcount, "questions": questions} return result s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) host = '' port = 53 size = 512 s.bind((host, port)) while True: data, addr = s.recvfrom(size) pprint.pprint(decode_dns_message(data)) 

Y luego complete las funciones de deencoding de los registros restantes.