skip to content

Header, Rcodes and Transport

The DNS header flags, response codes such as NXDOMAIN and SERVFAIL, and when a query leaves UDP 53 for TCP after truncation or grows with EDNS0. 'Does DNS use TCP?' is a classic screen.

on this pageshow

questions

4

Does DNS use UDP or TCP, and when does a DNS query move from UDP port 53 to TCP?

level: juniorimportance: must knowfreq 62%

answer

  1. default transport and port
  2. a size ceiling from 1987
  3. a header bit that means too big
  4. ask again on another transport
  5. RFC 7766 made one of them mandatory

basics

~20 s

DNS uses both. Queries normally travel over UDP port 53; a response too large for UDP (512 bytes without EDNS0) comes back with the TC bit set, and the client repeats the query over TCP port 53, which RFC 7766 makes mandatory.

solid answer

~40 s

DNS runs over both UDP and TCP, on port 53 for each. Ordinary lookups use UDP because one small datagram each way is the cheapest exchange. RFC 1035 caps a plain UDP DNS message at 512 bytes, not counting the IP and UDP headers; EDNS0 (RFC 6891) lets the client advertise a larger size. When the answer still does not fit, the server truncates it and sets the `TC` bit, and the client discards that reply and asks again over TCP, where every message carries a two-byte length prefix. Full zone transfers (AXFR) also use TCP. RFC 7766 made TCP support mandatory for all general-purpose DNS implementations and relaxed RFC 1123's "UDP first" rule, so a client may even start on TCP.

code

pseudocode · 6 lines
pseudocode
function query_server(server, q):
    reply = udp_exchange(server, port=53, q)     # client retransmits on timeout
    if reply.header.TC == 1:
        # RFC 2181 section 9: ignore the truncated reply entirely
        reply = tcp_exchange(server, port=53, q)  # 2-byte length prefix per message
    return reply

go deeper

for a junior

Recall that DNS uses UDP port 53 by default and TCP port 53 when an answer is too big, and that the TC bit in the response is what tells the client to switch.

for a middle

Explain the sequence: the 512-byte classic limit, the server truncating and setting TC, the client discarding that reply and re-asking over TCP with a two-byte length prefix, and how EDNS0 moves the limit.

for a senior

Show the production consequence: blocking TCP 53 breaks lookups only when the answer is large, such as many records or a big TXT record, so the failure looks name-specific and intermittent rather than a total outage.

for a principal

Treat TCP as a first-class DNS transport, as RFC 7766 does: plan server capacity for connections, expect connection reuse, and write firewall policy that treats TCP 53 as required rather than optional.

## The short answer The **Domain Name System (DNS)** uses **both UDP and TCP**, and both use **port 53**. Most lookups are a single UDP datagram out and a single UDP datagram back. TCP is used when a response is too large for UDP, for full zone transfers, and whenever a client or server chooses it, because RFC 7766 treats TCP as a full alternative transport rather than a last resort. "DNS is a UDP protocol" is therefore half an answer, and in an interview it is the half that gets a follow-up. ## Why UDP is the default A typical DNS exchange is one question and one small answer. Over UDP that costs: - **one datagram each way**, with no connection set-up and no teardown; - **no per-client state** on the server, which matters to a server answering many clients at once; - **retransmission handled by the client**: RFC 1035 §4.2.1 notes that UDP queries may be lost, so the client retries, preferably against another server or address first. A TCP exchange would add a three-way handshake before the question can even be sent. For a short answer that is extra round trips for nothing, which is why UDP became "the recommended method for standard queries" in RFC 1035. ## The 512-byte limit and the TC bit RFC 1035 §4.2.1 restricts a DNS message carried over UDP to **512 bytes, not counting the IP or UDP headers**. EDNS0 (RFC 6891) lets a client advertise that it can accept more, but whatever the limit is, some answers exceed it: many records at one name, a large `TXT` record, or a signed response. The sequence is: 1. The client sends its query over UDP to port 53. 2. The server builds the answer and finds it will not fit the limit that applies to this exchange. 3. The server returns what fits and sets the **`TC` (TrunCation) bit** in the header. 4. The client **ignores that truncated reply** and sends the same query over TCP to port 53. 5. The server answers over TCP. Each message is prefixed with a **two-byte length field**, so one TCP message can carry up to 65,535 bytes. RFC 2181 §9 tightens when `TC` may be set: only when an RRset that the response *requires* could not be included whole. If the only thing that does not fit is optional extra data (such as additional-section addresses), the server leaves that data out and sends the reply with `TC` clear. When `TC` is set, a partial RRset may be left in, and the client should not use it. ## What changes on TCP | Aspect | UDP | TCP | |---|---|---| | Port | 53 | 53 | | Message framing | one message per datagram | two-byte length prefix before each message | | Size ceiling | 512 bytes, or the EDNS0 size advertised | 65,535 bytes per message | | Set-up cost | none | three-way handshake first | | Typical use | ordinary queries | truncated answers, full zone transfers, connection reuse | RFC 7766 adds three rules worth knowing: - **All general-purpose DNS implementations MUST support TCP**: authoritative servers, recursive resolvers and stub resolvers alike. - The old RFC 1123 requirement to send a UDP query first is **relaxed**: a resolver MAY use TCP before any UDP query, and SHOULD reuse an open TCP connection to the same server. - A server **MUST reply on the transport the query arrived on**, and for TCP on the same connection. The server never "switches to TCP" on its own; the client re-asks. ## Why this matters in production Because truncation affects only large answers, a network that blocks TCP port 53 breaks ordinary lookups **selectively**. Names with small answers keep resolving; a name with many records or a big `TXT` record fails. That pattern looks like a problem with one domain when it is really a transport problem. The same selectivity applies when large UDP answers are lost on the path, which is the EDNS0 sizing problem. ## Common misconceptions - **"TCP is only for zone transfers."** Full zone transfers (AXFR) do need TCP, but any truncated answer also moves to TCP, and RFC 7766 lets clients use TCP from the start. - **"The 512 bytes include the headers."** They do not; RFC 1035 counts the DNS message only. - **"A TC reply is still usable."** The client should discard it and re-query, because the RRset it needs may be incomplete.

  • Does a truncated DNS response still contain records a client can use?
    It may contain some, but the client should not use them. RFC 2181 section 9 says `TC` is set only when a required RRset could not be included whole, and a partial RRset may be left in; the client should ignore that response and query again over a transport that permits larger replies, normally TCP. If only optional additional data did not fit, the server omits it and leaves `TC` clear.
  • If TCP mostly matters for large answers, why does RFC 7766 require stub resolvers to support it too?
    A stub that cannot speak TCP can never receive an answer larger than its UDP limit, so any such name simply fails for its applications. RFC 7766 says stubs MUST support TCP because anything else limits interoperability with upstream servers, and it notes that signed responses routinely exceed 512 bytes; an NXDOMAIN from an NSEC3-signed zone almost always does.
  • Over TCP, how does a DNS server know where one message ends and the next begins?
    Each DNS message on a TCP connection is preceded by a two-byte length field giving the message length, excluding the field itself (RFC 1035 section 4.2.2). That framing lets several queries share one connection. RFC 7766 allows them to be pipelined and answered out of order, so the client matches each response to its query by the header's ID.

A letter too big for the envelope: the sender posts back a slip saying the reply did not fit, and you go to the counter to collect it whole. You do not act on the torn page that came with the slip.

saying these in an interview costs you the question

  • DNS only ever uses UDP; TCP is just for zone transfers.
  • Blocking TCP port 53 is safe because ordinary lookups never need it.
  • A response with the TC bit set can be used as-is, just missing a few records.
  • The 512-byte UDP limit includes the IP and UDP headers.
  • The DNS server switches the conversation to TCP by itself when an answer is large.
  • RFC 1123 still requires every DNS query to try UDP first.
open as a page

What do the DNS response codes NOERROR, NXDOMAIN, SERVFAIL and REFUSED mean, and how does a NODATA answer differ from NXDOMAIN?

level: middleimportance: must knowfreq 48%

basics

~20 s

NOERROR (0) is success, NXDOMAIN (3) says the name does not exist, SERVFAIL (2) that the server could not answer, REFUSED (5) a policy refusal. NODATA is not an rcode: NOERROR with an empty answer, so the name exists without that type.

open as a page

Reading a DNS response header, what do the ID field and the QR, AA, RD and RA flags tell you about who answered and how?

level: middleimportance: should knowfreq 30%

basics

~20 s

The 16-bit ID pairs the reply with its query; QR=1 marks a response; AA=1 means the server is authoritative for the queried name; RD echoes whether recursion was requested; RA says whether the server offers recursion at all.

open as a page

A DNS name carrying several large TXT records resolves on most networks but times out behind one firewall; how do EDNS0's advertised UDP size, IP fragmentation and TCP fallback explain it?

level: seniorimportance: should knowfreq 20%

basics

~20 s

The resolver's EDNS0 OPT record advertises a large UDP size, so the server sends the answer untruncated; above the path MTU it is fragmented, the firewall drops the fragments, and with no reply there is no TC bit to prompt a TCP retry.

open as a page