Prefácio
Eu decidi escrever um sniffer DNS, por assim dizer, apenas por diversão. Basta ver quais endereços estão sendo resolvidos no meu sistema. O protocolo é antigo, deve haver muita documentação. Muito. Mas todos os artigos são muito incompletos e terminam, no momento mais interessante. Sim, há rfc1035, mas eu gostaria em russo e com explicações. De fato na acumulação de experiência e análise de um pacote este artigo amadureceu. Ele foi desenvolvido para quem entende o que é o DNS e entende que há solicitações e respostas. Para quem quer entender um pouco da estrutura deste protocolo.
O artigo envolve teoria e, em seguida, um pouco de prática.
Estrutura de pacotes DNS
+---------------------+ | Header | +---------------------+ | Question | +---------------------+ | Answer | +---------------------+ | Authority | +---------------------+ | Additional | +---------------------+
Cabeçalho - O cabeçalho do pacote DNS, composto por 12 octetos.
Seção de perguntas - nesta seção, o cliente DNS transmite consultas ao servidor DNS informando sobre o nome para o qual é necessário resolver (resolver) o registro DNS e também o tipo (NS, A, TXT etc.). Ao responder, o servidor copia essas informações e as devolve ao cliente na mesma seção.
Seção Resposta - o servidor informa ao cliente a resposta ou várias respostas à solicitação, nas quais ele informa os dados acima.
Seção autoritativa - contém informações sobre quais servidores autoritativos obtiveram as informações incluídas na seção de resposta do DNS.
Seção Registro Adicional - registros adicionais relacionados à solicitação, mas que não são respostas estritamente à pergunta.
Pode haver várias ou poucas entradas nas seções. Tudo é determinado pelo cabeçalho.
Estrutura de cabeçalho 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) - esse campo é usado como um identificador de transação exclusivo. Indica que o pacote pertence à mesma sessão "solicitação-resposta" e ocupa 16 bits.
QR (1 bit) - esse bit é usado para identificar se o pacote é uma solicitação (QR = 0) ou uma resposta (QR = 1).
Opcode (4 bits) - usando esse código, o cliente pode especificar o tipo de solicitação, onde o valor usual é:
- 0 - solicitação padrão
- 1 - solicitação inversa,
- 2 - solicitar status do servidor.
- 3-15 - reservado para o futuro.
AA (1 bit) - esse campo só faz sentido nas respostas DNS do servidor e informa se a resposta é autorizada ou não.
TC (1 bit) - esse sinalizador é definido no pacote de resposta se o servidor não puder colocar todas as informações necessárias no pacote devido a restrições existentes.
RD (1 bit) - esse sinalizador de um bit é definido na solicitação e copiado para a resposta. Se o sinalizador estiver definido na solicitação, isso significa que o cliente solicita ao servidor que não informe respostas intermediárias, mas que retorne apenas o endereço IP.
RA (1 bit) - enviado apenas em respostas e relata que o servidor suporta recursão
Z (3 bits) - são reservados e sempre iguais a zero.
RCODE (4 bits) - este campo é usado para notificar os clientes se a solicitação foi concluída com sucesso ou com um erro.
- 0 - significa que a solicitação foi aprovada sem erros;
- 1 - o erro se deve ao fato de o servidor não entender o formulário de solicitação;
- 2 - este erro com operação incorreta do servidor de nomes;
- 3 - o nome que permite ao cliente não existir neste domínio;
- 4 - o servidor não pode atender a solicitação deste tipo;
- 5 - este código significa que o servidor não pode atender à solicitação do cliente devido a restrições administrativas de segurança.
QDCOUNT (16 bits) - o número de registros na seção de consulta
ANCOUNT (16 bits) - o número de entradas na seção de respostas
NSCOUNT (16 bits) - número de entradas na seção Autoridade
ARCOUNT (16 bits) - o número de registros na seção Registro adicional
Estrutura da seção de solicitação
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 solicitação e resposta começa com NAME. Este é o nome de domínio ao qual esse registro está vinculado ou ao qual "pertence". É codificado como uma série de tags. Neste ponto, devemos nos debruçar com mais detalhes.
Nos artigos que eu vi, eles esquecem de dizer que o protocolo DNS original fornece dois tipos de rótulos, que são determinados pelos dois primeiros bits:
00 (etiqueta padrão) - significa que os 6 bits restantes determinam o comprimento da etiqueta, seguido por um número determinado de octetos. Consequentemente, o comprimento do rótulo não pode ser superior a 63 bytes (por exemplo, o nslookup exibirá a mensagem "não é um nome legal (rótulo muito longo)" ao tentar reduzir um host com um rótulo longo). A gravação termina com o código 0x00.
11 (etiqueta compactada) - os próximos 14 bits definem um link para o endereço inicial da série de etiquetas. Como a experiência demonstrou, também pode conter uma etiqueta compactada para outro endereço. Na solicitação, como regra, não existem esses rótulos.
Além disso, o rótulo pode conter o valor 0x00 (comprimento zero), o que significa que é o nome do domínio raiz (raiz).
O comprimento máximo de NAME é <= 255. Isso é para facilitar a implementação.
QTYPE - O tipo de registro DNS que estamos procurando (NS, A, TXT etc.).
QCLASS - A classe de solicitação de definição (IN para a Internet).
Estrutura da seção de resposta
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 / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
NOME - Mesmo formato que QNAME na seção de solicitação.
TYPE - tipo de registro de recurso. Define o formato e a finalidade desse registro de recurso.
CLASS - classe de registro de recurso; acredita-se teoricamente que o DNS pode ser usado não apenas com TCP / IP, mas também com outros tipos de redes, o código no campo da classe determina o tipo de rede. Basicamente IN para Internet (código 0x0001)
TTL - (Time To Live) - o tempo de armazenamento válido para esse registro de recurso no cache de um servidor DNS não responsivo.
RDLENGTH - comprimento do campo de dados (RDATA).
RDATA - campo de dados, cujo formato e conteúdo dependem do tipo de registro.
Prática
Considere um pacote de uma solicitação e resposta reais. Inicie o seu sniffer favorito e resolva o habrahabr.ru.
Pedido
Vamos analisar a estrutura do cabeçalho dns.
ID da transação = 0x9bce
Em seguida estão as bandeiras. 01 00 é representado como um valor binário 0'0000'0'0'1'0'000'0000 (a seguir, separo os bits com um apóstrofo para uma melhor representação visual da divisão da bandeira)
QR = 0 - significa que este pacote é uma solicitação;
Opcode = 0000 - solicitação padrão;
AA = 0 - este campo faz sentido apenas nas respostas DNS, portanto sempre 0;
TC = 0 - esse campo faz sentido apenas nas respostas DNS, portanto sempre 0;
RD = 1 - Por favor, retorne apenas o endereço IP;
RA = 0 - enviado apenas pelo servidor;
Z = 000 - sempre zeros, campo reservado;
RCODE = 0000 - Tudo correu sem erros
QDCOUNT = 00 01 - 1 entrada na seção de consulta
ANCOUNT = 00 00 - A solicitação é sempre 0, seção para respostas
NSCOUNT = 00 00 - A solicitação é sempre 0, seção para respostas
ARCOUNT = 00 00 - A solicitação é sempre 0, seção para respostas
Em seguida, temos as seções de solicitação e resposta. Com uma entrada.
O primeiro octeto que temos é 0x09, imagine-o como um valor binário 00'001001. Os dois primeiros bits vão 00, o que significa que esse é um rótulo comum. Comprimento da etiqueta 9 bytes (b001001). "68 61 62 72 61 68 61 62 72". Estes são 9 bytes. Diz "habrahabr" (em hexadecimal). Vá em frente. Octeto 0x02. Os dois primeiros bits são 00 e, novamente, um rótulo regular com um comprimento de 2 bytes. Aqui estão eles: "72 75". Está escrito "ru". Vá em frente. Octeto 0x00. Isso significa o fim da entrada do host. Temos duas palavras "habrahabr" e "ru". Nós os unimos com um ponto, obtemos “habrahabr.ru”, este é o host que solicitamos.
QTYPE = 0x0001 - Corresponde ao tipo A (solicitação de endereço do host)
QCLASS = 0x0001 - Corresponde à classe IN.
A resposta
Vamos analisar a estrutura do cabeçalho dns.
ID da transação = 0x9bce. Deve ser exatamente o ID da solicitação.
Sinalizadores novamente. 81 80 representa o valor binário 1'0000'0'0'1'1'000'0000
QR = 1 - significa que este pacote é a resposta;
Opcode = 0000 - solicitação padrão;
AA = 0 - O servidor não é autoritário para o domínio;
TC = 0 - Todas as informações cabem em um pacote;
RD = 1 - Por favor, retorne apenas o endereço IP;
RA = 1 - O servidor suporta recursão;
Z = 000 - sempre zeros, campo reservado;
RCODE = 0000 - Tudo correu sem erros
QDCOUNT = 00 01 - 1 entrada na seção de consulta
ANCOUNT = 00 01 - Agora temos uma entrada na resposta
NSCOUNT = 00 00 - A solicitação é sempre 0, seção para respostas
ARCOUNT = 00 00 - A solicitação é sempre 0, seção para respostas
Em seguida, temos as seções de solicitação e resposta. Com duas entradas. Um registro da solicitação, outro registro com a resposta. Não pintarei a seção de solicitação, ela sempre será 1v1 igual à do pacote de solicitação. Prossiga com a seção de respostas.
O primeiro octeto é 0x09, os dois primeiros bits são 00, o que significa um rótulo comum com um comprimento de 9 bytes. Leia 9 bytes, obtenha "HABRAHABR". Em seguida, vem 0XC0 (b11000000). Como você pode ver, os dois primeiros bits têm um valor de 11, o que significa que temos um link compactado. Observamos os próximos 8 bits (temos 0x16 (b00010110)) e combinamos com os últimos 6 bits atuais. Temos b00000000010110. Link para o 22º byte do pacote DNS (02 72 75 00). Começando no 22 de outubro, obtemos os rótulos novamente. Pelas mesmas regras. Nós entendemos .ru. Combinamos tudo o que recebemos, verifica-se "HABRAHABR.ru" Este é o host, que será discutido mais adiante.
QTYPE = 0x0001 - Corresponde ao tipo A (solicitação de endereço do host)
QCLASS = 0x0001 - Corresponde à classe IN.
TTL = 0x00000c90 - tempo de atividade dos dados 3216 segundos.
RDLENGTH = 0x0004 - O comprimento dos dados é de 4 octetos.
RDATA = "b2 f8 ed 44".
Como já mencionado, o formato e o conteúdo dependem do tipo de gravação. O tipo de registro que temos é "A". Portanto, para obter o IP, precisamos ler 4 bytes. Cada byte é o octeto correspondente do endereço IP, escrito em hexadecimal.
Obtemos o IP: b2.f8.ed.44 ou "178.248.237.68". O que era necessário para receber.
Por exemplo, para o tipo NS, o formato seria:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / NSDNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
E leríamos o nome de acordo com as regras do QNAME.