Networking & Protocols
The resolver walk: referrals, record types, and glue
A resolver asking for cdn.example.co.uk does not get an answer from the root server. It gets a referral — “ask the .uk TLD.” Then another referral — “ask example.co.uk’s authoritative server.” Only on the third query does it get an actual IP address. Understanding what travels in those referral responses is what separates a developer who can debug DNS from one who just runs dig and hopes.
Iterative vs recursive queries
The resolver’s queries to root, TLD, and authoritative servers are iterative: the RD (Recursion Desired) bit is cleared. Those servers return only what they know, plus a referral — they never chase the tree for the caller. Only the client’s original query to the resolver has RD=1, asking the resolver to do the full walk.
This distinction matters for security. An authoritative server that accepts RD=1 from external clients — an open resolver — can be abused as a DNS-reflection amplifier: an attacker sends spoofed-source queries and the server sends large responses to the victim. Production authoritatives (Route 53, Cloudflare DNS) never recurse for external clients.
DNS message sections
A DNS message has four sections:
| Section | Purpose |
|---|---|
| Question | The query name, type (A, MX, …), class (IN) |
| Answer | Records that directly answer the question |
| Authority | NS records pointing to the next-hop nameserver |
| Additional | Pre-fetched A/AAAA records for names in Authority |
A referral has nothing in Answer, and has Authority + Additional. The AA (Authoritative Answer) bit is set only when the responding server owns the zone — a referral from a TLD server has AA=0.
The referral chain for cdn.example.co.uk
- Resolver → root: asks for
cdn.example.co.uk. Root has no answer. It returns Authority:ns.nic.uk(NS record for.uk), plus Additional:ns.nic.uk A 193.0.0.1(glue). No Answer section. - Resolver →
.ukTLD: asks same QNAME. TLD returns Authority:ns1.example.co.uk(NS forexample.co.uk), plus Additional:ns1.example.co.uk A 198.51.100.4(glue). Still no Answer. - Resolver → authoritative: asks same QNAME. Authoritative returns Answer:
cdn.example.co.uk A 203.0.113.10 TTL=300. AA bit set.
Trace a cold DNS lookup of cdn.example.co.uk from a clean cache.
Glue records and the circular dependency
When a zone delegates to a nameserver inside its own zone (the NS for example.com is ns1.example.com), the parent zone must include the A record for ns1.example.com as glue in the referral. Without glue, the resolver cannot find the nameserver without first resolving example.com — a chicken-and-egg loop.
Missing glue causes intermittent SERVFAIL or referral loops. Out-of-bailiwick NS records (e.g., ns1.somednsprovider.org) need no glue because the resolver can ask a different zone for their IP.
- A
- IPv4 address
- AAAA
- IPv6 address
- CNAME
- alias → another name (never an IP)
- MX
- mail server hostname + priority
- TXT
- free text — SPF, DKIM, verification
- NS
- delegation — nameserver for the zone
- SOA
- zone authority: serial, refresh, TTL mins
- CAA
- which CAs may issue certs for this domain
- HTTPS/SVCB
- advertises ALPN + ECH keys (RFC 9460)
CNAME and the apex rule
A CNAME record points a name to another name: www CNAME example.com. The resolver then looks up the target. CNAME is forbidden at the zone apex (the bare domain like example.com) per RFC 1034, because SOA and NS records must also exist at the apex, and CNAME would override every other record type at that name. CDN-specific ALIAS/ANAME records and the new HTTPS record (RFC 9460) work around this.
When a recursive resolver gets a referral from a TLD server, where does next-hop information come from?
Why is CNAME forbidden at the zone apex (example.com) per RFC 1034?
UDP, TCP, and EDNS0
DNS defaults to UDP port 53. If a response exceeds the UDP buffer, the server sets the TC (truncation) flag and the resolver retries over TCP port 53. TCP is also required for zone transfers (AXFR/IXFR). A firewall that blocks TCP/53 while allowing UDP/53 silently breaks DNSSEC responses and zone transfers.
EDNS0 (RFC 6891) adds an OPT pseudo-record to negotiate larger UDP buffers (typically 1232 or 4096 bytes) and carry extension options including the DNSSEC OK (DO) bit, ECS (client subnet), and EDNS Cookies. Every modern resolver advertises EDNS0; without it DNSSEC responses are truncated.
Order the steps when a client opens https://shop.example.com from a clean cache:
- 1 Browser asks OS resolver for shop.example.com
- 2 OS resolver forwards to configured upstream (ISP or 1.1.1.1)
- 3 Resolver walks root → .com → example.com authoritative
- 4 Resolver returns A record (IP) to browser
- 5 Browser performs TCP handshake to that IP
- 6 Browser performs TLS handshake on top of TCP
- 7 Browser sends HTTPS request and receives the page
Why this works
Stub resolver vs full recursive resolver. Your operating system runs a stub resolver — a thin client that forwards queries to a configured upstream and caches briefly. Linux uses systemd-resolved or nscd; macOS uses mDNSResponder; Windows uses the DNS Client service. The stub does almost no work itself. The full recursive resolver — the one that walks root→TLD→authoritative — lives upstream (your router, ISP, or a public resolver like 1.1.1.1). Browsers often bypass the OS stub entirely: Chrome’s Async DNS Resolver and Firefox’s TRR query DoH directly. Flushing the OS stub cache (sudo systemd-resolve --flush-caches) does not flush the upstream resolver’s cache.
- 01What is the operational difference between an authoritative server and a recursive resolver?
- 02Why must glue records exist for in-bailiwick nameservers?
- 03Why does DNS fall back from UDP to TCP for some queries?
A recursive resolver walks the DNS tree iteratively, collecting referrals at each level. Each referral carries NS records in the Authority section plus glue A/AAAA records in Additional — together they break any circular dependency for in-bailiwick nameservers. The AA (Authoritative Answer) bit is only set when the responding server owns the zone. DNS record types go far beyond A records: CNAME aliases names, MX routes mail, TXT carries SPF/DKIM, NS delegates zones, SOA defines zone authority. CNAME is forbidden at the zone apex because SOA and NS must co-exist there. DNS defaults to UDP; large responses (DNSSEC, zone transfers) fall back to TCP. EDNS0 extends UDP buffers and carries DNSSEC flags.
appears again in152
- Why GraphQL gets N+1junior
- DataLoader mechanics: tick-boundary batchingmiddle
- Batch function contracts: ordering, shapes, errorsmiddle
- Federation and lookahead: batching beyond DataLoadermiddle
- Query complexity defences: depth, cost, persisted queriesmiddle
- Senior GraphQL API: scheduling contract, tenant isolation, observabilitysenior
- Why idempotency: making retries safejunior
- Server-side state machine: four states of an idempotency keymiddle
- Outbox and inbox: effectively-once across the dual-write boundarymiddle
- Concurrency and cache architecture for idempotency at scalesenior
- Observability, production failures, and global-scale designsenior
- The event loop: one thread, three queuesjunior
- Tasks, microtasks, and scheduler.yield()middle
- Microtask starvation, Long Tasks, and LoAFsenior
- Node.js event loop: phases, nextTick, and loop lagsenior
- React, Vue, and INP observability in productionsenior
- The render pipeline: six stages from bytes to pixelsjunior
- Stage costs and the renderer process modelmiddle
- Invalidation, dirty bits, and containmiddle
- Compositor layers: promotion, overlap, and GPU memorymiddle
- DevTools flame strip and the frame lifecyclemiddle
- Layout thrash: forced synchronous layoutsenior
- BeginMainFrame, compositor-driven animations, and GPU memorysenior
- Production observability: LoAF, INP, and the full attack surfacesenior
- What V8 is and why performance varies 100×junior
- V8''''s four-tier JIT pipeline and profile-guided tieringmiddle
- Hidden classes, transition trees, and memory layoutmiddle
- Inline caches, IC states, and deoptimizationmiddle
- Orinoco GC: parallel scavenger, concurrent marking, and write barriersmiddle
- TurboFan''''s speculative engine and the deopt-loop trapsenior
- V8 in production: isolates, pointer compression, and real failuressenior
- Service worker lifecycle and cache strategiesmiddle
- Service worker edge cases: version skew, durability, and navigation trapssenior
- What the reconciler does: render vs commitjunior
- The fiber object and the double-buffer treemiddle
- Render phase purity and commit phase sub-stepsmiddle
- Reconciliation: diffing heuristics and the key trapmiddle
- Priority lanes, time-slicing, and useTransitionmiddle
- Bailout, memoisation, and tearingsenior
- React Profiler, the Compiler, and production observabilitysenior
- Rendering strategies: SSG, SSR, ISR, streaming, and hydrationjunior
- SSG, SSR, ISR, streaming, and RSC — how each worksmiddle
- Hydration cost: selective, progressive, islands, resumabilitymiddle
- Hydration mismatch: causes, detection, and the determinism rulesenior
- RSC, per-route strategy, and production observabilitysenior
- Core Web Vitals: what LCP, INP, and CLS measurejunior
- CLS: why layout shifts happen and how to stop themmiddle
- Metric tradeoffs, RUM attribution, and the CI+field loopsenior
- The full picture: URL to LCP to INP as a relay racejunior
- Eight layers traced: from the service worker to the second navigationmiddle
- Five canonical breaks: where production reliably diessenior
- The three-track method: reading traces and building a monitored systemsenior
- What is a cache stampede and why it makes things worsejunior
- Lock and single-flight: bounding concurrent rebuildsmiddle
- XFetch: coordination-free probabilistic early expirationmiddle
- Stale-while-revalidate and CDN request coalescingmiddle
- Detecting stampedes and designing TTL for productionmiddle
- Metastable failure, fencing tokens, and production postmortemssenior
- What a relation is: tables, rows, keys, and constraintsjunior
- Constraints, keys, and Postgres data typesmiddle
- Normal forms, denormalization, and why schemas stickmiddle
- JSONB, arrays, and when a side table winsmiddle
- Heap storage, TOAST, and column alignmentsenior
- Schema integrity: deferral, versioning, and production failure modessenior
- Relational vs document, wide-column, graph, and key-valuesenior
- Index-only scans, the Visibility Map, and INCLUDEsenior
- Production failure modes and the index audit playbooksenior
- pg_statistic, ANALYZE, and production observabilitymiddle
- Production failure modes and plan stabilitysenior
- MVCC: why readers and writers never wait for each otherjunior
- Row versions and snapshots: the on-disk mechanicsmiddle
- HOT updates and isolation levels: what you gain and what you paymiddle
- Vacuum and bloat: keeping the storage tax boundedmiddle
- CLOG, XID wraparound, and MultiXact: deep visibility internalssenior
- SSI internals and production autovacuum tuningsenior
- Real-world MVCC failures, deployment patterns, and distributed snapshotssenior
- Connection pools: amortising the cost of a Postgres backendjunior
- PgBouncer session, transaction, and statement modesmiddle
- Pool sizing: the (cores × 2) + spindles formula and the two-layer stackmiddle
- Pool exhaustion and idle-in-transaction: the 3 AM failure modemiddle
- Migrating to transaction mode: rollout playbook and PgBouncer 1.21 prepared statementsmiddle
- The Postgres process model and why raising max_connections degrades throughputsenior
- Pooler landscape 2026, serverless connection storms, and the full failure-mode taxonomysenior
- What a schema migration is and why it replaces ad-hoc DDLjunior
- ADD COLUMN: instant in PG 11+ vs rewrite in older Postgresjunior
- The lock-queue failure mode: why instant DDL can freeze the databasemiddle
- Safe DDL patterns: NOT VALID, CONCURRENTLY, and unsafe-op fixesmiddle
- Expand-contract: zero-downtime for breaking schema changesmiddle
- Advisory locks, migration tools, and deploy coordinationsenior
- Migration failure taxonomy and production disciplinesenior
- Why sharding exists: the single-Postgres ceilingjunior
- Shard-key selection: hash, range, list, and directory strategiesmiddle
- Partitioning vs sharding: same word, two different thingsmiddle
- Co-location and Citus: the invariant that makes sharding usablemiddle
- The hot-shard failure mode: detection, isolation, and durable policymiddle
- Schema-based sharding and multi-tenancy alternativessenior
- Online resharding, 2PC, and the operational cost of shardingsenior
- The seven acts: from CREATE TABLE to Citusjunior
- Acts 1–3 in depth: schema, indexes, and planner statisticsmiddle
- Acts 4–6 in depth: MVCC bloat, connection pooling, and safe migrationsmiddle
- Act 7 in depth: sharding, co-location, and the seven-tier tradeoff cascademiddle
- Observability, anti-patterns, and production triagesenior
- Raft roles, terms, and why majority quorums prevent split brainjunior
- How Raft replicates a log entry and decides it is safe to commitmiddle
- Raft leader election: timeouts, voting rules, and the four safety propertiesmiddle
- Raft in the real world: partitions, slow disks, and client routingmiddle
- Raft extensions: pre-vote, learners, snapshots, and linearizable readssenior
- Raft in production: membership changes, Multi-Raft, and observabilitysenior
- Where data fetching happens — and why it decides LCPjunior
- Fetch waterfalls — diagnosis and the Promise.all curemiddle
- React Server Components and Suspense streamingmiddle
- Client-side cache: TanStack Query, SWR, and stale-while-revalidatemiddle
- LCP, prefetch, and race conditions in interactive fetchingmiddle
- Senior internals: RSC payload, caching layers, and production failure modessenior
- What the three signals are: logs, metrics, and tracesjunior
- Why structured logs exist: the diary vs the spreadsheetjunior
- The production log schema: fields every line must carrymiddle
- PII redaction and log injectionsenior
- OTel Logs Data Model and audit logs as a subsystemsenior
- SLI, SLO, and the error budget: reliability by the numbersjunior
- Error budget policy, latency SLOs, and composite journeysmiddle
- Production SLO failures, self-observability, security, and the big picturesenior
- The incident loop: from pager to postmortem to preventionmiddle
- Cache lines, struct layout, and false sharingmiddle
- SIMD, SoA vs AoS, and memory bandwidthmiddle
- Cache-oblivious algorithms, PGO, and production failuressenior
- GC in production: observability, security, edge cases, and fleet governancesenior
- Batching: amortize fixed cost per operationjunior
- The batching window: size and wait timemiddle
- Batching in Kafka and Postgresmiddle
- io_uring and observability of batchingmiddle
- From Nagle to io_uring: evolution of batchingmiddle
- Backpressure, failure isolation, and batch security in productionsenior
- CI enforcement and RUM: making budgets stickmiddle
- V8 JIT pipeline, HTTP priorities, and bundle securitysenior
- The performance loop: discipline, not a projectjunior
- Classify and fix: matching bottleneck families to remediesmiddle
- Observability stack and CI gates: catching regressions before they shipmiddle
- Incident to enforcement: SLO burn to verified fix in 35 minutesmiddle
- Culture, economics, and org-scale performancesenior
- At-most-once, at-least-once, exactly-once: the three delivery contractsjunior
- The three failure legs — where duplicates and losses actually happenmiddle
- Consumer-side dedup: the cheapest path to exactly-once processingmiddle
- Kafka exactly-once semantics: idempotent producer and transactionsmiddle
- SQS visibility timeout, DLQ, and the outbox patternmiddle
- Exactly-once in production: impossibility proof, hybrid patterns, and real incidentssenior
- What OAuth is and why passwords are not the answerjunior
- Authorization code flow with PKCEmiddle
- ID token validation and JWKS cache managementmiddle
- Refresh token rotation and scope-based least privilegemiddle
- Sender-constrained tokens: DPoP and mTLSsenior
- OAuth in production: audience attacks, observability, and real failuressenior