<aside> 🧭

Module 04 · The Wire Protocol: UDP, TCP & EDNS(0)

Every dig response you have read carried an OPT PSEUDOSECTION that was never explained, a flags line you learned four letters of, and a size limit you have never hit. This module opens the packet. By the end, "does DNS use TCP or UDP?" stops being a trick question.

🧠 concept → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (answers hidden)

Prerequisite: Modules 01–03. You need the dig header, the five sections, RCODEs, referrals, and why a label is 63 octets.

</aside>

<aside> ⚠️

Run this module's exercises on a real machine, not inside a container behind a DNS proxy. Many sandboxes, corporate networks and container runtimes intercept port 53 and rewrite responses — they normalise EDNS buffer sizes, strip the tc bit, and answer on your behalf. If your output disagrees with what is shown here, that interception is the most likely reason, and discovering it is itself a useful finding about the network you are on.

</aside>


Part A · The DNS message

A1 · One format, for questions and answers alike

<aside> 📨

The analogy. Think of a standard order form.

The form the customer fills in and the form the shop sends back are the same printed sheet. The customer fills in the top box and leaves the rest blank. The shop fills in the rest and returns it.

That is why a DNS query and a DNS response have an identical structure — a query is just the same message with three sections still empty.

</aside>

<aside> 📖

Official docs: RFC 1035 §4 — Messages · RFC 9499 — DNS Terminology

</aside>

A DNS message is a 12-byte header followed by four sections. Queries and responses use the same structure — a query is simply a message with a filled-in question and three empty sections.

+---------------------+
|       HEADER        |  12 bytes, always
+---------------------+
|      QUESTION       |  what was asked
+---------------------+
|       ANSWER        |  records answering it
+---------------------+
|     AUTHORITY       |  NS records (referral) or SOA (negative)
+---------------------+
|     ADDITIONAL      |  glue, and the OPT pseudo-record
+---------------------+

You have been reading exactly this in every dig response. The header is the ->>HEADER<<- line plus the counters; the four sections are the four ;; ... SECTION: blocks.

<aside> 🔑

The header is only 12 bytes, and everything expensive about DNS follows from that. Two bytes of transaction ID, two bytes of flags and codes, and four two-byte counters — one per section. That is the entire control plane.

Because the counters are 16 bits, a message can in principle carry 65,535 records per section. Because the transaction ID is only 16 bits, there are only 65,536 possible values — and that number is the root of the spoofing problem in Part C.

</aside>


A2 · The flags, one bit at a time

<aside> ☑️

The analogy. Think of the tick boxes down the side of that form.

Some are ticked by you — "please deliver", "do not substitute". Some are ticked by the shop — "in stock", "checked by supervisor".

dig only prints the boxes that are ticked. So an empty box tells you as much as a ticked one: if the supervisor's box is blank, nobody checked it.

</aside>

<aside> 📖

Official docs: RFC 1035 §4.1.1 — Header section format · RFC 4035 §3.1.6 — the AD and CD bits · IANA DNS Parameters — DNS Header Flags

</aside>

dig prints the flags that are set and omits the rest. That is why the flags line is short and why an absent flag is as informative as a present one.

Flag Name Meaning, and who sets it
qr Query / Response Set in every response. Answerer
aa Authoritative Answer The answering server holds the zone. Answerer
tc TrunCated The response did not fit and was cut short. Answerer — Part B
rd Recursion Desired Please do the work for me. Asker
ra Recursion Available I am willing to. Answerer
ad Authentic Data The resolver DNSSEC-validated this. Answerer — Module 07
cd Checking Disabled Do not validate; give me the data unchecked. Asker — Module 07
do DNSSEC OK Not a header flag at all — it lives in the OPT record. Asker — B3