DNS Protocol and Resolution

39 min read
On this page

After modifying a domain's A record, some users see the new address immediately, while others still access the old one. This is usually not because DNS slowly broadcasts an update across all servers; rather, authoritative data, recursive caches, and system/application caches each maintain their own state. Understanding a single resolution requires distinguishing who is responsible for the data, who queries on behalf of whom, which results are cached, and whether the response indicates "does not exist" or "query failure."

QuestionEntry Point in This Article
What do root, recursive, and authoritative servers do?Delegation and Query Roles
Why is glue needed when NS records exist?Startup dependency for resolving authoritative server addresses
How to read a DNS packet?12-byte header, sections, labels, and compression pointers
When does a modification take effect?RRset TTL, negative caching, and hierarchical caching
Why do large responses require TCP?EDNS advertisement, Path MTU, and truncation
How do secondary servers synchronize?AXFR/IXFR vs. recursive caching differences

Namespace, Domain, and Zone

A DNS name consists of hierarchical labels, ending with a root label; the trailing dot in www.example.com. explicitly denotes an absolute name. A domain describes a subtree in the name tree, while a zone is the range of data managed by a set of authoritative servers; after a parent zone delegates a subdomain, the parent retains the delegation information but no longer authoritatively manages all records in the subzone.

DNS does not only return addresses: MX expresses mail exchange targets, TXT carries application convention information, and SRV expresses service locations, etc. A set of records with the same owner name, type, and class constitutes an RRset, which is a more suitable model than "one domain corresponds to one IP" for explaining caching, signing, and multiple addresses. RFC 1034: DNS Concepts

Stub, Forwarder, Recursive Resolver, and Authoritative Server

The recursive resolver accesses the authoritative hierarchy separately; authoritative servers do not forward requests layer by layer on its behalf Client / Stub Requests final answer Recursive Resolver Caching, Iteration, Validation Root Zone Server Returns com. Delegation com. Server Returns example.com. Delegation example.com. Authoritative Returns Target RRset Cold cache conceptual flow Some steps can be skipped if cached Forwarders hand off to upstream resolvers Each line represents a corresponding query/response transaction; in practice, resolving NS addresses, following aliases, or performing DNSSEC validation may also be required.

A stub typically hands queries over to a configured resolver service. A forwarder hands work off to an upstream, a recursive resolver can track delegations itself or forward under certain policies, and an authoritative server answers for its own zones. A single software can assume multiple roles; do not equate a product name directly with a fixed architecture.

RD indicates the client requests recursion, and RA indicates the server supports recursion; this does not guarantee that every RD=1 query is allowed to be recursive. A cold-cache recursive resolver can start from root hints, then find the next set of servers based on referrals; if delegation or answers are already cached, there is no need to ask the root every time.

Authoritative layers typically do not forward requests layer by layer for this specific query; the recursive resolver is the one actually initiating multiple queries. It may also generate additional queries due to NS addresses, aliases, and validation needs. One cannot rigidly state that there are exactly three queries in total each time, nor should one treat unmeasured "dozens of queries" as a universal overhead.

QNAME Minimization Changes Information Exposed Upstream

Traditional iteration might hand the complete target name to each level of servers; QNAME minimization tries to ask only the name parts necessary to advance the delegation for the current level. For example, the upstream does not necessarily need to know the full www.example.com. Specific QTYPE and fallback procedures are handled according to the algorithm; one cannot treat an NS query in a simplified diagram as the only unique online sequence for all implementations. RFC 9156: QNAME Minimization

Glue Unlocks Address Dependencies

If the NS for example.com. is ns1.example.com., the resolver needs to find the address of this NS before querying the subzone, but the address itself is within the subzone. The parent zone can provide glue addresses to help bootstrap. This is not the same trust level as the address RRset obtained and verified from the true authoritative source.

The Additional section does not mean its content can be cached unconditionally; the resolver must perform correlation and bailiwick checks. When NS records are outside the zone, their addresses may need to be resolved separately; not every referral includes A/AAAA for all NS records, and not all Additional addresses are called glue.

Message Structure: Locate Sections First, Then Parse Records

The basic DNS message header is 12 bytes, containing ID, Flags, and counts for Question/Answer/Authority/Additional. For TCP transport, a two-byte length prefix is placed before each DNS message; this prefix is not included in the DNS message offset; TCP is a byte stream, and a single read operation does not guarantee receiving exactly one complete message. RFC 1035: Message Format, RFC 7766: DNS over TCP

Flags MaskMeaning
0x8000QR: Query or Response
0x7800OPCODE field, requires shifting for interpretation
0x0400AA: Authoritative Answer flag
0x0200TC: Truncated
0x0100 / 0x0080RD / RA
0x0020 / 0x0010AD / CD, DNSSEC-related semantics
0x000fBase RCODE, EDNS extensible

The three Z bits in historical diagrams cannot be uniformly treated as three zero bits in modern messages; AD/CD already have purposes. The bit map numbering from left to right differs from the code's least significant bit numbering; using masks helps avoid inversion. ID matching is only one condition for associating responses; endpoint, question, and context must also be verified.

The Question section contains QNAME, QTYPE, QCLASS; a standard resource record contains NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. RDATA is interpreted according to TYPE; one cannot treat all types as a single string or a compressible domain name.

Labels and Compression: Complete 33 → 49 B Example

The online labels for www.example.com. are length 3 + www, length 7 + example, length 3 + com, and a final zero-length root label, totaling 17 B. Adding the 12 B header, 2 B QTYPE, and 2 B QCLASS, a single-question A query is 33 B.

If the response contains an A record with the same name, c0 0c can be used to point to the QNAME at offset 12 from the start of the DNS message. The record itself requires 2 B for the NAME pointer, 10 B for fixed fields, and 4 B for the IPv4 address, totaling 16 B; keeping the same question, the response totals 49 B. Without compressing the NAME, it would require 17+10+4=31 B, saving 15 B here; one cannot estimate arbitrarily based on the number of name repetitions. RFC 1035: Name Compression

Standard labels are at most 63 B, and complete online names have a total length limit; the high two bits of a compression pointer are 11, and the low 14 bits are the offset relative to the entire DNS message. The resolver must check for out-of-bounds, loops, and expansion length; one cannot chase pointers given by an attacker infinitely. The TCP length prefix does not change the internal DNS position indicated by c00c.

After the pointer jumps, where does the record's cursor stop?

c00c jumps from 33 to 12 to expand the name, but the Answer's TYPE still starts from 35. Switching to a pointer pointing to 33 itself causes the read position to enter the visited set, and parsing must be rejected; one cannot rely on "reading a few more steps" to luck into an end.

Preparing the visual
After the pointer jumps, where does the record's cursor stop?

A compression pointer occupies two bytes at the original position, but expansion can read labels from a distance. The position for recursively reading the name is not equal to the position of subsequent fields in the original record; anomalous pointers must terminate.

Record Types and Resolution Dependencies

TypeReading MethodCommon Misconception
A / AAAAIPv4 / IPv6 AddressNo AAAA does not mean the entire name does not exist
CNAMECurrent owner is an alias for another nameUsually, standard A/MX etc. data cannot be configured simultaneously with the same owner
NSPoints to authoritative server namesNS targets are names, not direct IP locations
MXLower preference is higher priority, followed by mail target nameDoes not guarantee the lowest value target is always available
SOAZone management, serial number, and sync/negative cache related fieldsMINIMUM is not the unified TTL for all positive records
PTRQueries target name in reverse namespaceNot the same mechanism as historical IQUERY opcode
SRVpriority, weight, port, targetpriority and weight cannot be mixed as the same sorting number
TXTOne or more length-prefixed stringsSingle string limit does not mean the entire RR is forever limited to 255 B
CAADNS data constraining certificate issuance authorizationDoes not encrypt DNS, nor directly verify the certificate currently being displayed

IPv4 reverse lookup, such as querying 10.2.0.192.in-addr.arpa. for 192.0.2.10's PTR, is a standard query. PTR does not have an automatic one-to-one correspondence guarantee with forward A/AAAA; one cannot rely solely on reverse lookup names to authenticate host identity.

CNAME tracking may trigger target queries; aliases and target RRsets each have their own TTL; standard CNAMEs conflict with the mandatory SOA/NS at the zone apex. Hosting platform ALIAS/flattening behavior does not cancel the coexistence rules for standard online CNAMEs.

Caching: Separate Positive Results, Negative Results, and Failures

TTL is the remaining lifespan of each cache copy, not a globally synchronized countdown switch t=0 t=100 t=200 t=300 s Recursive Resolver Caches Old A Initial TTL=300 s Authoritative Changes to New A Old cache still has 200 s remaining Old Copy Expires Next request can fetch again Other caches fetch at different times; lowering the new TTL does not retroactively shorten the old TTL already issued, and serve-stale has specific exceptions.

TTL controls how long a cache copy can be used under corresponding rules; it does not notify existing connections to switch addresses. The recursive resolver caches an old A with TTL=300 at t=0; the authoritative server changes the value at t=100, and the old copy may still be used until t=300. Changing the new record's TTL to 30 at this point will not retroactively modify the already issued 300.

Lowering the TTL before migration requires leaving time for old caches to expire naturally; actual user paths may also have application caches, negative caches, and different views. Some resolvers provide expired data under specific failure conditions via the serve-stale mechanism, which requires explicit policy and cannot be broadly considered as all TTLs becoming invalid. RFC 8767: serve-stale

ResponseMeaningCache Interpretation
NXDOMAIN, RCODE=3Query name does not existName-level negative result, needs context like aliases
NOERROR but no data for target typeOften called NODATA, not an independent RCODEName exists but type is missing, needs SOA etc. for judgment
SERVFAIL, RCODE=2Unable to complete, e.g., upstream/validation failureCannot be treated as authoritative proof that the name does not exist
REFUSED, RCODE=5Server policy refusalDoes not indicate whether the domain name itself exists

The regular negative cache TTL takes the smaller value of the response SOA's TTL and SOA.MINIMUM; the resolver may also apply local limits. If the two are 600 and 300, the negative cache base value is 300 s; a record just created that originally did not exist might also be temporarily hidden by an existing negative cache. RFC 2308: Negative Caching

Why doesn't the cache sync changes when the authoritative server updates?

At t=140, the old copy has 160 seconds remaining, and the new copy has only 10 seconds remaining; newer does not mean it expires later. After t=150, the second copy can no longer be used according to standard TTL rules, but this does not mean the first copy fails simultaneously.

Preparing the visual
Why doesn't the cache sync changes when the authoritative server updates?

TTL is attached to the fetched copy. The authoritative modification of content and new TTL does not retroactively rewrite the expiration time of old cache entries.

EDNS, Truncation, and Path Size

The traditional DNS/UDP message limit without EDNS is 512 B. EDNS uses the OPT pseudo-record in the Additional section to express capabilities: TYPE=41, CLASS is used to advertise UDP payload size, and the original TTL position carries extended RCODE, version, and flags. It is not a standard cacheable domain name RR, and DO does not equal validation success. RFC 6891: EDNS

Advertising the ability to receive 4096 B does not prove the path can carry 4096 B without fragmentation. A budget of 1232 B is based on the IPv6 minimum MTU of 1280 − 40 B IP header − 8 B UDP header; if there is more overhead, it still needs to be considered. Responses exceeding the applicable UDP limit can be truncated and the TC flag set, prompting the client to use TCP or other appropriate transports to fetch the complete result.

TCP is not just a dedicated channel for zone transfers; it is also an important transport that must be supported for standard queries. Filtering TCP 53 might make small queries seem normal while large responses fail; simply increasing the EDNS value might instead introduce IP fragmentation issues. RFC 7766

DNSSEC validates data source and integrity, while encrypted DNS protects the selected transport link; the two solve different problems. AA is not cryptographic authentication, and the trustworthiness of AD also depends on the trust relationship between the local machine and the resolver used; this will be expanded upon in the next article.

Zone Transfers: Synchronizing Authoritative Copies, Not Updating Global Recursive Caches

AXFR is a full zone transfer, spanning multiple DNS messages, carried over TCP, and delimited by SOA and other rules. IXFR requests increments based on serial numbers; if the server has no suitable delta, it may fall back to a full transfer. Serial number comparison has its own wrap-around rules and cannot always be judged by standard integer size for old vs. new. RFC 5936: AXFR

Primary/secondary synchronization completion only indicates that the authoritative copy is updated; it cannot force internet recursive resolvers to clear caches that have not yet expired. NOTIFY can prompt corresponding secondary servers to check for changes, but it is not equivalent to a global cache invalidation broadcast.

Locally Constructed Q&A

import struct
from ipaddress import IPv4Address

def encode_name(name):
    labels = name.rstrip('.').split('.')
    result = b''.join(bytes([len(x.encode('ascii'))])+x.encode('ascii') for x in labels)+bytes(1)
    assert all(0<len(x.encode('ascii'))<=63 for x in labels)
    assert len(result)<=255
    return result
qname = encode_name('www.example.com.')
question = qname+struct.pack('!HH',1,1)
query = struct.pack('!6H',0x1234,0x0100,1,0,0,0)+question
assert len(qname)==17 and len(query)==33
answer = bytes.fromhex('c00c')+struct.pack('!HHIH',1,1,300,4)+IPv4Address('192.0.2.10').packed
response = struct.pack('!6H',0x1234,0x8180,1,1,0,0)+question+answer
assert len(answer)==16 and len(response)==49
pointer = int.from_bytes(answer[:2],'big')&0x3fff
assert pointer==12 and response[pointer:pointer+17]==qname
flags = struct.unpack('!H',response[2:4])[0]
assert flags&0x8000 and flags&0x0080 and not flags&0x0400
assert 1280-40-8==1232
assert min(600,300)==300
assert max(0,300-100)==200
assert IPv4Address('192.0.2.10').reverse_pointer=='10.2.0.192.in-addr.arpa'
print('DNS Query/Response Length, Compression Offset, Flags, Negative Cache, and EDNS Budget Passed')

The example generates a fixed instructional A response; it is not a complete DNS parser or cache implementation; all addresses are used for documentation examples and do not query or modify real domain names.

Continue Reading