2 DNS
Watersrc-stack edited this page 2026-10-14 04:00:21 +02:00

DNS

The Domain Name System turns names into addresses (example.com → 192.0.2.2), and addresses back into names. A client sends a query to a resolver, usually over UDP port 53, and gets a response with the same 16-bit id. Queries and responses share one message format.

The message

+---------------------+
|       Header        |  12 bytes
+---------------------+
|      Question       |  what is asked
+---------------------+
|       Answer        |  resource records that answer it
+---------------------+
|      Authority      |  records pointing to the authoritative servers
+---------------------+
|     Additional      |  extra records (EDNS options...)
+---------------------+

Header

 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|  Opcode   |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
|                    ANCOUNT                    |
|                    NSCOUNT                    |
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Field Meaning
ID Chosen by the client and copied into the response. It should be random, because a predictable id lets an attacker forge an answer.
QR 0 = query, 1 = response
Opcode 0 = standard query
AA, TC authoritative answer; truncated (retry over TCP)
RD, RA recursion desired (by the client); recursion available (from the server)
AD, CD DNSSEC: authenticated data; checking disabled
RCODE 0 NOERROR, 2 SERVFAIL, 3 NXDOMAIN (no such name), 5 REFUSED
counts how many entries each section has

Names

A name is a list of labels, each preceded by its length, ending with a 0 byte. example.com is:

07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
 7  e  x  a  m  p  l  e  3  c  o  m  end

To save space, a name can end with a pointer to an earlier name in the same message: two bytes starting with the bits 11, the other 14 bits being an offset. c0 0c means "the name at offset 12", which is the question's name, since the header is 12 bytes. Pointers can point to pointers, so a careless parser can be sent into a loop.

Question and resource records

A question is a name, a type (2 bytes) and a class (2 bytes, 1 = IN). Record types:

Type Value Holds
A 1 an IPv4 address
NS 2 a name server's name
CNAME 5 another name (an alias)
PTR 12 a name, for reverse lookups
MX 15 a mail server
TXT 16 text
AAAA 28 an IPv6 address
OPT 41 EDNS options (a pseudo-record)
HTTPS 65 HTTPS service parameters (ALPN, ECH...)

A resource record is: name, type, class, TTL (4 bytes, seconds it may be cached), data length (2 bytes), data.

Example: query and answer

The query, after the UDP header:

9e 28 01 20 00 01 00 00 00 00 00 01 07 65 78 61
6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29
04 d0 00 00 00 00 00 0c 00 0a 00 08 41 f8 43 a3
bc b7 57 11
Bytes Field Value
9e 28 ID 0x9e28
01 20 Flags 0000 0001 0010 0000: query, RD (recursion desired), AD
00 01 00 00 00 00 00 01 Counts 1 question, 0 answers, 0 authority, 1 additional
07 example 03 com 00 Question name example.com
00 01 00 01 Type, class A, IN
00 00 29 04 d0 00 00 00 00 Additional: OPT root name, type 41 (EDNS): UDP size 1232, no extended flags
00 0c 00 0a 00 08 … OPT data 12 bytes: option 10 (cookie), 8 random bytes

The answer:

9e 28 81 80 00 01 00 01 00 00 00 00 07 65 78 61
6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00
01 00 01 00 00 01 2c 00 04 c0 00 02 02
Bytes Field Value
9e 28 ID same as the query
81 80 Flags 1000 0001 1000 0000: response, RD, RA, RCODE 0 (NOERROR)
00 01 00 01 00 00 00 00 Counts 1 question (repeated), 1 answer
07 example 03 com 00 00 01 00 01 Question example.com, A, IN
c0 0c Answer: name pointer to offset 12: example.com
00 01 00 01 Type, class A, IN
00 00 01 2c TTL 300 s
00 04 c0 00 02 02 Data 4 bytes: 192.0.2.2

The IPv6 lookup asks for type AAAA (00 1c) and gets 16 bytes back: 20 01 0d b8 … 00 02, which is 2001:db8::2.

Reverse lookups: PTR

To find the name of 192.0.2.1, the client asks for a PTR record under a special domain:

  • IPv4: the address bytes reversed, under in-addr.arpa. 192.0.2.1 becomes 1.2.0.192.in-addr.arpa.
  • IPv6: the 32 hex digits, one label each, reversed, under ip6.arpa. 2001:db8::1 becomes 1.0.0.0.…8.b.d.0.1.0.0.2.ip6.arpa (74 bytes once encoded).

A query NetOtter sent, and its answer:

Reverse DNS query #13505 for 192.0.2.1 -> 192.0.2.2:53 (40 bytes)
  0000  34 c1 01 00 00 01 00 00  00 00 00 00 01 31 01 32  |4............1.2|
  0010  01 30 03 31 39 32 07 69  6e 2d 61 64 64 72 04 61  |.0.192.in-addr.a|
  0020  72 70 61 00 00 0c 00 01                           |rpa.....|
Reverse DNS answer #13505: client.example.com (72 bytes)
  0000  34 c1 81 80 00 01 00 01  00 00 00 00 01 31 01 32  |4............1.2|
  0010  01 30 03 31 39 32 07 69  6e 2d 61 64 64 72 04 61  |.0.192.in-addr.a|
  0020  72 70 61 00 00 0c 00 01  c0 0c 00 0c 00 01 00 00  |rpa.............|
  0030  0e 10 00 14 06 63 6c 69  65 6e 74 07 65 78 61 6d  |.....client.exam|
  0040  70 6c 65 03 63 6f 6d 00                           |ple.com.|
  • Query: flags 01 00 (just RD), then labels 1, 2, 0, 192, in-addr, arpa, then type 00 0c (PTR) and class IN.
  • Answer: the record's data is a name, client.example.com, 20 bytes long (00 14).

When no name exists, the server answers NXDOMAIN (flags 81 83: RCODE 3).

Over TCP and encrypted

Transport When
UDP 53 Almost every query.
TCP 53 When the answer was truncated (TC), and zone transfers. Messages get a 2-byte length prefix.
DNS over TLS (port 853), DNS over HTTPS (443), DNS over QUIC Encrypted: the network can't read the names.

In NetOtter

  • Hostname learning: dns_learn() (Parsers) reads UDP answers from port 53. Each A / AAAA record maps its address to the question name, so a CNAME chain still names the address after what was asked. dns_read_name() follows at most 16 pointers and caps names at 255 characters.
  • Analysis view: after the answer above, 192.0.2.2 is shown as example.com in i (Dest. host example.com).
  • Reverse lookups: NetOtter's own PTR queries are built by build_query(); see Reverse DNS and privacy.
  • Not decoded: DNS over TCP, DoT and DoH.

Read more