A (RFC) 1035 dá a toda mensagem DNS o mesmo header (cabeçalho) de 12 bytes (RFC 1035, seção 4.1.1), que o dig imprime nas linhas ->>HEADER<<- e flags: que quase todo mundo pula. Esses bytes dizem quem respondeu, se houve oferta de recursão, se a resposta foi cortada, se um resolver a garante sob as Domain Name System Security Extensions () e como o pedido acabou. Na parte 4 de DNS, lido a partir da resposta, você decodifica uma troca real em hexadecimal e lê cada campo pelo que ele conta a um diagnóstico.

Doze bytes, como a RFC 1035 os desenha

Seis palavras de 16 bits, desenhadas em 1987 (RFC 1035, seção 4.1.1):

                                    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                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

O bit 0 é o mais significativo, e o byte alto viaja primeiro (RFC 1035, seção 2.3.2). O ID é "A 16 bit identifier assigned by the program that generates any kind of query", um identificador de 16 bits escolhido por quem pergunta, que a resposta copia (seção 4.1.1). As flags são (query ou resposta), AA (Authoritative Answer), TC (Truncated Response), RD (Recursion Desired) e RA (Recursion Available), ao lado de um opcode de 4 bits e de um (código de resposta) de 4 bits; o dig rotula os quatro contadores de seção como QUERY, ANSWER, AUTHORITY e ADDITIONAL (dig.c).

Z, os bits 9 a 11, era "Reserved for future use. Must be zero in all queries and responses" (RFC 1035, seção 4.1.1), até a RFC 2535 tomar dois desses bits para o DNSSEC em 1999, (Authentic Data) e CD (Checking Disabled) (RFC 2535, seção 6.1). A palavra hoje é lida assim (RFC 6895, seção 2):

             |QR|   OpCode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |

Resta um bit reservado, que só uma Standards Action pode atribuir (RFC 6895, seção 2.1). Na numeração do registro da Internet Assigned Numbers Authority () (IANA, parâmetros do DNS), o bit n vale 2 elevado a 15 menos n:

bit      0     1-4     5     6     7     8     9     10    11    12-15
campo    QR    Opcode  AA    TC    RD    RA    Z     AD    CD    RCODE
máscara  8000  7800    0400  0200  0100  0080  0040  0020  0010  000F

Uma consulta real e sua resposta, byte a byte

Capturado em 18 de outubro de 2026: os registros NS (servidor de nomes) de example.com, pedidos a um resolver público por (), que leva a mensagem no formato de fio, header na frente (RFC 8484, seção 4.1.1). A consulta:

0000  11 49 01 20 00 01 00 00  00 00 00 01 07 65 78 61
0010  6d 70 6c 65 03 63 6f 6d  00 00 02 00 01 00 00 29
0020  04 d0 00 00 00 00 00 00

11 49 é o ID, 0x1149 = 4.425, e 01 20 são as flags; os contadores são 1, 0, 0 e 1. Do byte 12 vêm example.com, o tipo 2 (NS) e a classe 1 (IN); os 11 últimos bytes são um pseudorregistro OPT das Extension Mechanisms for DNS (), tipo 41, oferecendo um payload UDP de 1.232 bytes (RFC 6891, seção 6.1.2). A resposta começa:

0000  11 49 81 a0 00 01 00 02  00 00 00 01 07 65 78 61
0010  6d 70 6c 65 03 63 6f 6d  00 00 02 00 01

Mesmo ID e mesma pergunta; os contadores são 1, 2, 0 e 1. Os bytes 29 a 83 são os dois registros NS, o primeiro abrindo com c0 0c, um ponteiro para o deslocamento 12 contado a partir do ID (RFC 1035, seção 4.1.4); os bytes 84 a 94 são o OPT do resolver, porque "If an record is present in a received request, compliant responders MUST include an OPT record in their respective responses", OPT recebido, OPT devolvido (RFC 6891, seção 6.1.1). As flags, contra as máscaras:

           QR    Opcode  AA    TC    RD    RA    Z     AD    CD    RCODE
consulta   0     0000    0     0     1     0     0     1     0     0000    0x0120
resposta   1     0000    0     0     1     1     0     1     0     0000    0x81a0

RD (256) e AD (32) somam os 288 da consulta, 0x0120; a resposta acrescenta QR (32.768) e RA (128): 32.768 + 256 + 128 + 32 = 33.184, 0x81a0. RD volta como foi, AA é zero porque um resolver respondeu, RCODE 0 é NOERROR (No Error), e AD é um porque example.com é assinado e a consulta pediu (RFC 6840, seção 5.8). Ilustrativo, pelos formatos do dig 9.20.29, o par como +qr o mostraria (dig.c):

;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4425
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4425
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

ADDITIONAL: 1 sem nenhuma seção adicional impressa é normal: o contador inclui o registro OPT, que o dig imprime à parte sob ;; OPT PSEUDOSECTION: (message.c), e uma resposta ininteligível aparece só como ;; Got bad packet: (dighost.c). EDNS e a pseudosseção OPT lê esse bloco.

O que as flags contam a um diagnóstico

QR e AA. Uma saída sem qr é uma consulta, já que QR só vale 1 em respostas (RFC 1035, seção 4.1.1). AA "specifies that the responding name server is an authority for the domain name in question section", quem respondeu é autoridade para o nome (seção 4.1.1), embora atrás de um alias só o registro do alias seja autoritativo com certeza (RFC 2181, seção 5.4.1). As respostas de um resolver, até um NXDOMAIN (Non-Existent Domain) legítimo, normalmente vêm sem aa; uma resposta autoritativa a uma consulta com RD seria 0x8500, QR AA RD (ilustrativo). Veja Respostas autoritativas e não autoritativas.

RD e RA. "If RD is set, it directs the name server to pursue the query recursively", RD pede recursão, e a resposta copia o bit (RFC 1035, seção 4.1.1); o dig o liga a menos que receba +norecurse (manual do dig). RA é a oferta: "That is, RA signals availability rather than use", RA sinaliza disponibilidade, não uso (RFC 1034, seção 4.3.1). Para rd sem ra, o dig avisa recursion requested but not available (dig.c); um servidor autoritativo ainda responde pelas próprias zonas e costuma devolver REFUSED para as outras (RFC 9520, seção 2.2).

AD e CD. Um resolver validador só liga AD quando considera autênticos os registros de resposta e de autoridade (RFC 4035, seção 3.2.3) e a consulta trouxe AD ou o bit DNSSEC OK (DO) (RFC 6840, seção 5.8), como as do dig trazem por padrão (manual do dig). É uma alegação, não uma prova: um resolver "MUST disregard the meaning of the CD and AD bits in a response unless the response was obtained by using a secure channel", fora de um canal seguro CD e AD não valem (RFC 4035, seção 4.6). Confie em ad só vindo de um resolver validador confiável, por um canal confiável (RFC 4033, seção 7).

CD desliga a validação para uma consulta e volta copiado (RFC 4035, seção 3.2.2); uma validação que falha devolve SERVFAIL (Server Failure), a menos que a consulta tenha ligado CD (seção 5.5). Daí o teste do Internet Systems Consortium (ISC), editor do dig: "If the query succeeds with dig +cd, but ends in SERVFAIL without it, you know you are dealing with a validation problem", sucesso só com +cd é problema de validação (ISC, DNSSEC Guide). Em 18 de outubro de 2026 um resolver público respondeu assim ao domínio que o guia mantém para falhar (192.0.2.53 representa o seu):

dig @192.0.2.53 www.dnssec-failed.org A
dig @192.0.2.53 www.dnssec-failed.org A +cd
sem CD  04 6e 81 82 00 01 00 00 00 00 00 01   0x8182: qr rd ra, SERVFAIL, sem resposta
com CD  84 33 81 90 00 01 00 02 00 00 00 01   0x8190: qr rd ra cd, NOERROR, 2 respostas

DNSSEC de ponta a ponta explica a validação.

TC: quando a resposta não cabe

A RFC 1035 limitou as mensagens UDP a 512 bytes, fora os headers IP e UDP, truncando as maiores com TC ligado (RFC 1035, seção 4.2.1). A RFC 2181 estreitou a regra a um conjunto de registros (RRSet) que faltou: "The TC bit should be set in responses only when an RRSet is required as a part of the response, but could not be included in its entirety", TC só quando um RRSet necessário não coube inteiro. Quem recebe TC deve ignorar a resposta e perguntar de novo por um transporte que admita respostas maiores, como o TCP (RFC 2181, seção 9).

O DNSSEC tornou corriqueiro o truncamento nos 512 bytes (RFC 7766, seção 4), e a RFC 7766 decidiu: "All general-purpose DNS implementations MUST support both UDP and TCP transport", UDP e TCP obrigatórios (seção 5). As redes também: "Likewise, network operators MUST allow DNS service over both UDP and TCP transports", o operador de rede também (RFC 9210, seção 3). Um bloqueio de TCP falha em silêncio: as pequenas passam por UDP e só as grandes falham (RFC 7766, seção 1).

O dig repete por TCP por padrão (manual do dig), anotando Truncated, retrying in TCP mode. (dighost.c); +ignore fica com a resposta UDP truncada e +tcp testa diretamente a porta TCP 53 do servidor (RFC 1035, seção 4.2.2):

dig +ignore @192.0.2.53 example.com
dig +tcp @192.0.2.53 example.com

Uma resposta truncada de um resolver seria lida como flags: qr tc rd ra, 32.768 + 512 + 256 + 128 = 33.664 = 0x8380 (ilustrativo). O montador de comandos dig escreve os dois comandos; Anatomia de uma linha de comando dig os explica.

Opcode e status: os códigos que você vai encontrar

O opcode é definido por quem origina a mensagem e copiado na resposta (RFC 1035, seção 4.1.1), cada unidade somando 2.048 à palavra de flags (IANA, parâmetros do DNS):

OpcodeNomePalavra de flagsNota
0QUERY0x0000toda consulta comum
1IQUERY (consulta inversa)0x0800obsoleto (RFC 3425, seção 3)
2STATUS0x1000nunca especificado (RFC 6895, seção 2.2)
4NOTIFY0x2000aviso de zona alterada; o pedido liga AA, 0x2400 (RFC 1996, resumo e seção 4.5)
5UPDATE0x2800atualização dinâmica; QR é sua única flag (RFC 2136, seção 2.2)
6DSO (DNS Stateful Operations)0x3000por TCP ou TLS; o dig imprime RESERVED6 (RFC 8490, seção 4.2; dig.c)

O status é o RCODE (RFC 1035, seção 4.1.1); os códigos que você vai encontrar, com as descrições do registro (IANA, parâmetros do DNS):

CódigoStatusDescrição no registroEm geral significa
0NOERRORNo Errorprocessado; resposta vazia é
1FORMERRFormat Errornão entendido, muitas vezes EDNS (RFC 9520, seção 2.7)
2SERVFAILServer Failuresem dados válidos, ou validação falhou (RFC 9520, seções 2.1 e 2.6)
3NXDOMAINNon-Existent Domaino nome não existe
4NOTIMPNot Implementedtipo de consulta ou opcode sem suporte (RFC 2136, seção 2.2)
5REFUSEDQuery Refusedpolítica, ou zona que o servidor não serve (RFC 9520, seção 2.2)
16BADVERSBad OPT Versionversão EDNS não implementada

NODATA não tem código próprio: "NODATA responses have to be algorithmically determined from the response's contents as there is no RCODE value to indicate NODATA", é deduzido do conteúdo da resposta (RFC 2308, seção 2.2). Resolvers devem guardar um SERVFAIL em cache de 1 segundo a 5 minutos, e uma falha já corrigida pode demorar a sumir (RFC 9520, seção 3.2).

O EDNS alarga o RCODE para 12 bits: o primeiro byte do campo de RCODE estendido e flags do registro OPT fornece os oito de cima (RFC 6891, seção 6.1.3); o dig imprime a soma, esse byte vezes 16 mais os quatro bits do header (message.c). Duas capturas do mesmo dia:

dig +edns=1 +showbadvers example.com NS
example.com NS, EDNS versão 1   15 b6 81 80 00 01 00 00 00 00 00 01  qr rd ra; OPT: RCODE estendido 1
no-such-name.invalid A          e7 26 81 a3 00 01 00 00 00 01 00 01  qr rd ra ad; RCODE 3

O primeiro header diz RCODE 0, mas seu OPT acrescenta RCODE estendido 1: 1 × 16 + 0 = 16, BADVERS, obrigatório para uma versão EDNS não implementada (RFC 6891, seção 6.1.3); o dig tenta de novo com a versão 0, a menos que receba +showbadvers (manual do dig). O segundo é um NXDOMAIN repassado por um resolver, AA em zero, com o SOA da zona raiz na autoridade, cujo tempo de vida limita o cache negativo (RFC 2308, seção 3). O nome fica sob .invalid porque example.com hoje responde NOERROR sem dados a nomes inexistentes, pela negação compacta de existência (RFC 9824, seção 1), enquanto a RFC 6761 deixa o usuário assumir que nomes em .invalid sempre retornam NXDOMAIN (RFC 6761, seção 6.4).

O ID, a porta de origem e as respostas forjadas

A RFC 5452 obriga a conferência completa, endereços, porta, ID, nome, classe e tipo: "A mismatch and the response MUST be considered invalid", qualquer divergência invalida a resposta (RFC 5452, seção 9.1). O dig sorteia o ID a cada consulta e avisa ID mismatch ante uma resposta estranha (dighost.c).

Um resolver com cache aceita a primeira resposta que cumpra quatro condições, entre elas o ID igual e a chegada no endereço e na porta de onde a pergunta saiu, e depois serve a seus clientes o que tiver aceitado (RFC 5452, seção 3). Um ID aleatório de 16 bits, sozinho, "will require on average 32768 attempts to guess", exige em média 32.768 tentativas (seção 4.3); uma porta de origem aleatória acrescenta até 16 bits (seção 4.5), e em largura total a média passa a 32.768 × 65.536 = 2.147.483.648. Por isso a RFC 5452 exige uma porta imprevisível na faixa mais larga praticável e "Use an unpredictable query ID for outgoing queries, utilizing the full range available (0-65535)", um ID imprevisível em toda a faixa (seção 9.2). A nota VU#800113 (julho de 2008) creditou a a demonstração de quão prático era envenenar um cache, e a a ideia original das portas aleatórias (CERT Coordination Center, VU#800113), como conta A falha de Kaminsky.

Há limites: dispositivos de que serializam ou restringem as portas de origem podem reduzir drasticamente o ganho (RFC 5452, seção 10), e "protocol users are not protected against third parties with the ability to observe, modify, or inject packets in the traffic of a resolver", nada disso protege de quem injeta pacotes no caminho (seção 1), caso deixado ao DNSSEC.

Como ver o header na prática

No dig, +qr mostra a consulta como foi enviada, e +qid=valor, +opcode=valor e +zflag definem o ID, o opcode e o Z para testes (manual do dig); Opções de consulta e controle de saída do dig tem o resto. Um script precisa ler o status, pois o dig sai com 0 também em NXDOMAIN (manual do dig, Return Codes). O tcpdump marca RD ligado com +, AA ligado com *, RA desligado com - e TC ligado com | (tcpdump(1)); os campos do Wireshark estão listados abaixo (Wireshark, campos de DNS); e em Python struct.unpack('!HHHHHH', data[:12]) devolve as seis palavras na ordem de bytes da rede (Python, struct).

tcpdump -n -X 'port 53'
dns.id  dns.flags  dns.flags.response  dns.flags.opcode  dns.flags.authoritative
dns.flags.truncated  dns.flags.recdesired  dns.flags.recavail  dns.flags.z
dns.flags.authenticated  dns.flags.checkdisable  dns.flags.rcode  dns.resp.ext_rcode
dns.count.queries  dns.count.answers  dns.count.auth_rr  dns.count.add_rr  dns.response_to

O explicador de saída do dig lê as linhas de header e de flags coladas, explica as sete flags e avisa sobre tc, falta de qr e do sem ad. O playground Python empacota um header DNS com struct; o explicador de saída do nslookup diz se uma resposta é autoritativa.

Para lembrar

  • O header tem 12 bytes, seis palavras de 16 bits: o ID, a palavra de flags e quatro contadores de seção.
  • A palavra de flags é uma soma de máscaras: QR 0x8000, RD 0x0100, RA 0x0080 e AD 0x0020 dão 0x81a0, um NOERROR validado de um resolver.
  • RD volta copiado, RA é a oferta do servidor, e AA marca o servidor da própria zona, ausente nas respostas de um resolver.
  • TC quer dizer que um conjunto de registros necessário não coube: repita por TCP, que toda implementação deve suportar e toda rede deve permitir.
  • AD é uma alegação, confiável só vinda de um resolver validador confiável; SERVFAIL sem CD e resposta com CD indicam falha de DNSSEC.
  • O status é um RCODE de 12 bits, quatro bits no header mais oito no registro OPT, que ADDITIONAL conta embora o dig o imprima à parte.
  • O ID e a porta de origem precisam ser imprevisíveis: 16 bits sozinhos caem em 32.768 tentativas, em média.

Fontes