Prólogo
Decidí escribir un sniffer DNS, por así decirlo, solo por diversión. Solo vea qué direcciones se están resolviendo en mi sistema. El protocolo es antiguo, debe haber mucha documentación. Mucho Pero todos los artículos están muy incompletos y terminan, en el momento más interesante. Sí, hay rfc1035, pero me gustaría en ruso y con explicaciones. En realidad, sobre la acumulación de experiencia y el análisis de un paquete, este artículo ha madurado. Está diseñado para aquellos que entienden qué es DNS y entienden que hay solicitudes y respuestas. Para aquellos que quieran entender un poco en la estructura de este protocolo.
El artículo involucra teoría y luego un poco de práctica.
Estructura de paquetes DNS
+---------------------+ | Header | +---------------------+ | Question | +---------------------+ | Answer | +---------------------+ | Authority | +---------------------+ | Additional | +---------------------+
Encabezado : el encabezado del paquete DNS, que consta de 12 octetos.
Sección de preguntas : en esta sección, el cliente DNS transmite consultas al servidor DNS informando sobre el nombre para el que es necesario resolver (resolver) el registro DNS, así como sobre qué tipo (NS, A, TXT, etc.). Al responder, el servidor copia esta información y se la devuelve al cliente en la misma sección.
Sección de respuesta : el servidor le dice al cliente la respuesta o varias respuestas a la solicitud, en la que informa los datos anteriores.
Sección autoritativa : contiene información sobre los servidores autorizados que obtuvieron la información incluida en la sección de respuesta DNS.
Sección de registros adicionales: registros adicionales que se relacionan con la solicitud, pero que no son estrictamente respuestas a la pregunta.
Puede haber varias o pocas entradas en las secciones. Todo está determinado por el encabezado.
Estructura de encabezado DNS
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
ID (16 bits): este campo se utiliza como un identificador de transacción único. Indica que el paquete pertenece a la misma sesión de "solicitud-respuesta" y ocupa 16 bits.
QR (1 bit): este bit se utiliza para identificar si el paquete es una solicitud (QR = 0) o una respuesta (QR = 1).
Opcode (4 bits): con este código, el cliente puede especificar el tipo de solicitud, donde el valor habitual es:
- 0 - solicitud estándar
- 1 - solicitud inversa,
- 2: solicitar el estado del servidor.
- 3-15 - reservado para el futuro.
AA (1 bit): este campo solo tiene sentido en las respuestas DNS del servidor e informa si la respuesta es autorizada o no.
TC (1 bit): este indicador se establece en el paquete de respuesta si el servidor no pudo incluir toda la información necesaria en el paquete debido a las restricciones existentes.
RD (1 bit): este indicador de un bit se establece en la solicitud y se copia a la respuesta. Si el indicador se establece en la solicitud, esto significa que el cliente le pide al servidor que no le diga respuestas intermedias, sino que devuelva solo la dirección IP.
RA (1 bit): enviado solo en respuestas e informa que el servidor admite recursividad
Z (3 bits): están reservados y siempre son iguales a cero.
RCODE (4 bits): este campo se utiliza para notificar a los clientes si la solicitud se completó correctamente o con un error.
- 0: significa que la solicitud se pasó sin errores;
- 1 - el error se debe al hecho de que el servidor no pudo entender el formulario de solicitud;
- 2 - este error con una operación incorrecta del servidor de nombres;
- 3 - el nombre que permite que el cliente no exista en este dominio;
- 4 - el servidor no puede cumplir con la solicitud de este tipo;
- 5: este código significa que el servidor no puede satisfacer la solicitud del cliente debido a restricciones de seguridad administrativas.
QDCOUNT (16 bits): el número de registros en la sección de consulta
ANCOUNT (16 bits): el número de entradas en la sección de respuestas
NSCOUNT (16 bits): número de entradas en la sección Autoridad
ARCOUNT (16 bits): el número de registros en la sección de registros adicionales
Estructura de sección de solicitud
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
QNAME : cada registro de solicitud y respuesta comienza con NAME. Este es el nombre de dominio al que está vinculado este registro o al que "pertenece". Está codificado como una serie de etiquetas. En este punto, debemos insistir en más detalles.
En los artículos que vi, se olvidan de decir que el protocolo DNS original proporciona dos tipos de etiquetas, que están determinadas por los dos primeros bits:
00 (etiqueta estándar): significa que los 6 bits restantes determinan la longitud de la etiqueta, seguido de un número determinado de octetos. En consecuencia, la longitud de la etiqueta no puede ser superior a 63 bytes (por ejemplo, nslookup mostrará el mensaje "no es un nombre legal (etiqueta demasiado larga)" cuando intente sobrio un host con una etiqueta larga). La grabación termina con el código 0x00.
11 (etiqueta comprimida): los siguientes 14 bits definen un enlace a la dirección inicial de la serie de etiquetas. Como ha demostrado la experiencia, también puede contener una etiqueta comprimida a otra dirección. En la solicitud, por regla general, no existen tales etiquetas.
Además, la etiqueta puede contener el valor 0x00 (longitud cero), lo que significa que es el nombre de dominio raíz (raíz).
La longitud máxima de NAME es <= 255. Esto es para facilitar la implementación.
QTYPE : el tipo de registro DNS que estamos buscando (NS, A, TXT, etc.).
QCLASS : la clase de solicitud de definición (IN para Internet).
Estructura de la sección de respuesta
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / / / NAME / | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | CLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TTL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RDLENGTH | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| / RDATA / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
NOMBRE : el mismo formato que QNAME en la sección de solicitud.
TYPE : tipo de registro de recursos. Define el formato y el propósito de este registro de recursos.
CLASE - clase de registro de recursos; En teoría, se cree que el DNS se puede usar no solo con TCP / IP, sino también con otros tipos de redes, el código en el campo de clase determina el tipo de red. Básicamente IN para Internet (Código 0x0001)
TTL : (Tiempo de vida): el tiempo de almacenamiento válido para este registro de recursos en la memoria caché de un servidor DNS que no responde.
RDLENGTH : longitud del campo de datos (RDATA).
RDATA : campo de datos, cuyo formato y contenido depende del tipo de registro.
Practica
Considere un paquete de una solicitud y respuesta reales. Inicie su sniffer favorito y resuelva habrahabr.ru.
Solicitud
Analicemos la estructura del encabezado dns.
ID de transacción = 0x9bce
A continuación están las banderas. 01 00 se representa como un valor binario 0'0000'0'0'1'0'000'0000 (en adelante, separo los bits con un apóstrofe para una mejor representación visual de la división de la bandera)
QR = 0: significa que este paquete es una solicitud;
Opcode = 0000 - Solicitud estándar;
AA = 0: este campo solo tiene sentido en las respuestas de DNS, por lo tanto, siempre 0;
TC = 0: este campo solo tiene sentido en las respuestas de DNS, por lo tanto, siempre 0;
RD = 1: devuelva solo la dirección IP;
RA = 0: enviado solo por el servidor;
Z = 000 - siempre ceros, campo reservado;
RCODE = 0000 - Todo salió sin errores
QDCOUNT = 00 01 - 1 entrada en la sección de consulta
ANCOUNT = 00 00 - La solicitud siempre es 0, sección de respuestas
NSCOUNT = 00 00 - La solicitud siempre es 0, sección de respuestas
ARCOUNT = 00 00 - La solicitud siempre es 0, sección de respuestas
A continuación tenemos las secciones de solicitud y respuesta. Con una entrada.
El primer octeto que tenemos es 0x09, imagínelo como un valor binario 00'001001. Los primeros dos bits van a 00, lo que significa que esta es una etiqueta normal. Longitud de etiqueta 9 bytes (b001001). "68 61 62 72 61 68 61 62 72". Estos son 9 bytes. Dice "habrahabr" (en hexadecimal). Adelante Octeto 0x02. Los primeros dos bits son 00, luego nuevamente una etiqueta regular con una longitud de 2 bytes. Aquí están: "72 75". Está escrito "ru". Adelante Octeto 0x00. Esto significa el final de la entrada del host. Tenemos dos palabras "habrahabr" y "ru". Los unimos con un punto, obtenemos "habrahabr.ru", este es el host que solicitamos.
QTYPE = 0x0001: corresponde al tipo A (solicitud de dirección de host)
QCLASS = 0x0001 - Corresponde a la clase IN.
La respuesta
Analicemos la estructura del encabezado dns.
ID de transacción = 0x9bce. Debe ser exactamente la ID de la solicitud.
Banderas de nuevo. 81 80 representan el valor binario 1'0000'0'0'1'1'000'0000
QR = 1 - significa que este paquete es la respuesta;
Opcode = 0000 - Solicitud estándar;
AA = 0: el servidor no tiene autoridad para el dominio;
TC = 0: toda la información cabe en un paquete;
RD = 1: devuelva solo la dirección IP;
RA = 1: el servidor admite recursividad;
Z = 000 - siempre ceros, campo reservado;
RCODE = 0000 - Todo salió sin errores
QDCOUNT = 00 01 - 1 entrada en la sección de consulta
ANCOUNT = 00 01 - Ahora tenemos una entrada en la respuesta
NSCOUNT = 00 00 - La solicitud siempre es 0, sección de respuestas
ARCOUNT = 00 00 - La solicitud siempre es 0, sección de respuestas
A continuación tenemos las secciones de solicitud y respuesta. Con dos entradas. Un registro de la solicitud, otro registro con la respuesta. No pintaré la sección de solicitud, siempre será 1v1 igual que en el paquete de solicitud. Continúe con la sección de respuestas.
El primer octeto es 0x09, los dos primeros bits son 00, lo que significa una etiqueta regular con una longitud de 9 bytes. Lea 9 bytes, obtenga "HABRAHABR". Luego viene 0XC0 (b11000000). Como puede ver, los primeros dos bits tienen un valor de 11, lo que significa que tenemos un enlace comprimido. Observamos los siguientes 8 bits (tenemos 0x16 (b00010110)) y combinamos con los últimos 6 bits actuales. Obtenemos b00000000010110. Enlace al byte 22 del paquete DNS (02 72 75 00). Comenzando en el octeto 22, obtenemos las etiquetas nuevamente. Por las mismas reglas. Lo entendemos .ru. Combinamos todo lo que recibimos, resulta que "HABRAHABR.ru" Este es el host, que se discutirá más a fondo.
QTYPE = 0x0001: corresponde al tipo A (solicitud de dirección de host)
QCLASS = 0x0001 - Corresponde a la clase IN.
TTL = 0x00000c90: tiempo de actividad de datos 3216 segundos.
RDLENGTH = 0x0004 - La longitud de los datos es de 4 octetos.
RDATA = "b2 f8 ed 44".
Como ya se mencionó, el formato y el contenido dependen del tipo de grabación. El tipo de registro que tenemos es "A". Entonces, para obtener la IP, debemos leer 4 bytes. Cada byte es el octeto correspondiente de la dirección IP, escrito en hexadecimal.
Obtenemos la IP: b2.f8.ed.44 o "178.248.237.68". Lo que se requería para recibir.
Por ejemplo, para el tipo NS, el formato sería:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / NSDNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Y leeríamos el nombre de acuerdo con las reglas de QNAME.