DNS Resolution
Step 1: Check browser cache, OS `/etc/hosts`, local DNS resolver cache (e.g. 1.1.1.1 or 8.8.8.8). On cache miss, recursive query starts.
example.com. 3600 IN A 93.184.216.34 ; Maps hostname to 32-bit IPv4 addressWhat is DNS?
DNS (Domain Name System) translates human-readable domain names into IP addresses (and vice versa). It is the internet's distributed phone book.
"api.example.com" β DNS β "93.184.216.34"
DNS is a distributed, hierarchical, cached system β no single server knows everything; the answer is assembled through a chain of queries.
DNS Hierarchy
. (root)
/ | \
com org net io ... (TLDs β Top Level Domains)
/ | \
google example amazon (SLDs β Second Level Domains)
/
api www mail (Subdomains)
DNS Server Types
| Type | Role | Example |
|---|---|---|
| DNS Resolver (Recursive) | Queries on behalf of clients | 8.8.8.8 (Google), 1.1.1.1 (Cloudflare) |
| Root Nameserver | Knows TLD nameserver addresses | 13 root server clusters (aβm.root-servers.net) |
| TLD Nameserver | Knows authoritative NS for domains | Verisign (for .com), ICANN |
| Authoritative Nameserver | Has the actual records for a domain | Route 53, Cloudflare, your own NS |
DNS Resolution Process
Browser β OS β Resolver β Root β TLD β Authoritative
User types: api.example.com
1. Browser cache: api.example.com β ? (miss)
2. OS cache / /etc/hosts: ? (miss)
3. OS β Resolver (e.g., 8.8.8.8):
"What is api.example.com?"
4. Resolver β Root NS:
"Who handles .com?"
Root NS: "Ask a.gtld-servers.net"
5. Resolver β TLD NS (a.gtld-servers.net):
"Who handles example.com?"
TLD NS: "Ask ns1.example.com"
6. Resolver β Authoritative NS (ns1.example.com):
"What is api.example.com?"
Auth NS: "93.184.216.34, TTL 300"
7. Resolver caches: api.example.com β 93.184.216.34 (for 300s)
8. Resolver β Client: 93.184.216.34
9. Client caches result
10. Browser connects to 93.184.216.34:443
Full resolution typically takes 50β200ms; cached responses are < 1ms.
DNS Record Types
| Type | Name | Value | Use |
|---|---|---|---|
A | IPv4 Address | 93.184.216.34 | Map hostname β IPv4 |
AAAA | IPv6 Address | 2606:2800:220:1::... | Map hostname β IPv6 |
CNAME | Canonical Name | example.com | Alias β another hostname |
MX | Mail Exchanger | 10 mail.example.com | Email routing (with priority) |
TXT | Text | "v=spf1 include:..." | SPF, DKIM, domain verification |
NS | Name Server | ns1.example.com | Authoritative NS for zone |
SOA | Start of Authority | admin + serial + refresh | Zone metadata |
PTR | Pointer | example.com | Reverse DNS (IP β hostname) |
SRV | Service | 10 20 443 api.example.com | Service location (gRPC, SIP) |
CAA | CA Authorization | 0 issue "letsencrypt.org" | Which CAs may issue SSL certs |
CNAME Chains
api.example.com β CNAME β api-lb.cdn.example.com
api-lb.cdn.example.com β A β 203.0.113.50
Restriction: CNAME cannot coexist with other records at the same name
β Cannot put CNAME at zone apex (example.com itself) β use ALIAS/ANAME
MX Records and Priority
example.com MX 10 mail1.example.com (lowest priority = preferred)
example.com MX 20 mail2.example.com (backup)
example.com MX 30 mail3.example.com (last resort)
DNS TTL (Time To Live)
TTL controls how long DNS answers are cached by resolvers and clients.
api.example.com A 93.184.216.34 TTL=300 β cached for 5 minutes
Low TTL (30β60s):
β
Fast propagation when IP changes (failover, deployments)
β More DNS queries β higher load on nameservers
High TTL (3600β86400s):
β
Less DNS lookup overhead, fewer queries
β Slow to update on IP changes
Deployment strategy:
- Lower TTL to 60s a few hours before a change
- Make the DNS change
- After TTL passes, raise TTL back to normal
DNS Caching Layers
1. Browser DNS cache (chrome://net-internals/#dns)
2. OS DNS cache (nscd, systemd-resolved)
3. Router/modem cache
4. ISP resolver cache (your ISP's recursive resolver)
5. Public resolver cache (8.8.8.8, 1.1.1.1)
6. Authoritative server (source of truth)
# Flush OS DNS cache
# Linux (systemd-resolved)
sudo systemd-resolve --flush-caches
# macOS
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
# Windows
ipconfig /flushdns
# Query DNS directly
nslookup api.example.com 8.8.8.8
dig api.example.com @8.8.8.8
dig +trace api.example.com # full resolution chain
dig -x 93.184.216.34 # reverse DNS lookup
DNS Load Balancing
DNS can distribute traffic without a dedicated load balancer.
Round-Robin DNS
api.example.com A 10.0.0.1
api.example.com A 10.0.0.2
api.example.com A 10.0.0.3
Resolver rotates the order each query:
Query 1: [10.0.0.1, 10.0.0.2, 10.0.0.3] β client picks first
Query 2: [10.0.0.2, 10.0.0.3, 10.0.0.1] β client picks first
Limitations: no health checking β if one server dies, DNS still returns it.
GeoDNS / Latency-Based Routing
Serve different IPs based on the client's geographic location:
Client in US β api-us.example.com β 203.0.113.10 (US servers)
Client in EU β api-eu.example.com β 198.51.100.20 (EU servers)
Used by: Route 53 latency-based routing, Cloudflare GeoDNS.
DNSSEC
DNSSEC adds cryptographic signatures to DNS responses to prevent spoofing.
Without DNSSEC:
Attacker intercepts DNS response β returns malicious IP β cache poisoning
With DNSSEC:
Zone signs records with private key β DS record in parent zone
Resolver validates signature chain back to root (IANA)
Tampered responses fail signature check β rejected
# Verify DNSSEC
dig DNSKEY example.com
dig +dnssec A example.com # check AD (Authenticated Data) flag
Common DNS Issues & Diagnostics
DNS Propagation
After changing DNS records, old records may be cached globally for the duration of the TTL. "Propagation" is just waiting for caches to expire.
# Check from multiple global DNS resolvers
# whatsmydns.net β visual global propagation check
dig @8.8.8.8 example.com A # Google
dig @1.1.1.1 example.com A # Cloudflare
dig @9.9.9.9 example.com A # Quad9
Split-Horizon DNS
Different DNS answers for internal vs external clients:
Internal client: api.example.com β 10.0.0.5 (private IP)
External client: api.example.com β 203.0.113.5 (public IP/load balancer)
Used for: routing internal traffic through private network, keeping internal structure private.
Java DNS Configuration
// Java caches DNS results internally β configure TTL
// Default: 30s positive, 10s negative
// Set in jvm options or security properties
// $JAVA_HOME/conf/security/java.security
networkaddress.cache.ttl=30 // successful lookups
networkaddress.cache.negative.ttl=10 // failed lookups
// Or programmatically:
Security.setProperty("networkaddress.cache.ttl", "30");
// Spring Boot: use DNS-aware connection pool
// HttpClient automatically re-resolves on new connections
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.resolver(DefaultAddressResolverGroup.INSTANCE))) // DNS-aware
.baseUrl("https://api.example.com")
.build();
DNS on the Wire: UDP, TCP, EDNS and Encrypted DNS
- Queries normally use UDP port 53. The classic limit is 512 bytes. EDNS0 raises it (up to 4096), but since the 2020 DNS Flag Day resolvers advertise about 1232 bytes to avoid IP fragmentation.
- If the answer does not fit, the server sets the TC (truncated) bit and the client retries over TCP port 53. Zone transfers (AXFR) and large DNSSEC answers also use TCP, so blocking TCP/53 breaks DNS in subtle ways.
- DoT (DNS over TLS, port 853) and DoH (DNS over HTTPS, port 443) encrypt the stub-to-resolver hop. Note that DoH can bypass enterprise DNS filtering, and neither one encrypts the resolver-to-authoritative hop.
Negative Caching, CNAME Rules and Record Gotchas
- NXDOMAIN (name does not exist) and NODATA (name exists, no such type) are cached too, for the TTL given by the zone's SOA minimum / negative TTL (RFC 2308). A name created right after a failed lookup can stay "missing" for minutes.
- SERVFAIL means the resolver could not get an answer (broken DNSSEC, unreachable authoritative servers). It is a different failure from NXDOMAIN and resolvers may retry other servers.
- A CNAME cannot exist at the zone apex (it would conflict with the mandatory SOA and NS records) and cannot coexist with other records of the same name. Providers offer ALIAS/ANAME flattening for
example.compointing at a load balancer hostname. - Lowering a TTL only helps after the old TTL has expired. Before a migration, drop the TTL a full old-TTL period in advance, then cut over. Some resolvers and clients ignore low TTLs, so expect a long tail.
- DNS-based load balancing cannot drain a node precisely. Clients cache answers and ignore health, so pair it with real health checks and low TTLs, or use an L4/L7 load balancer.
dig +trace example.com # walk root -> TLD -> authoritative
dig +norecurse example.com @8.8.8.8 # cache-only check
dig example.com +tcp # confirm TCP/53 works
dig -x 93.184.216.34 # reverse lookup
Kubernetes DNS: The ndots:5 Trap
Pods get /etc/resolv.conf with several search domains and options ndots:5. A name with fewer than 5 dots is tried against each search suffix before being tried as an absolute name:
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
So resolving api.example.com (2 dots) first queries api.example.com.default.svc.cluster.local, then ...svc.cluster.local, then ...cluster.local (each returning NXDOMAIN), and only then the real name, for both A and AAAA. One lookup becomes about 8 queries.
Mitigations:
- Use a trailing dot (
api.example.com.) for external hosts in hot paths. - Set
dnsConfig.options: ndots: 2per pod when most lookups are external. - Run NodeLocal DNSCache to cache on each node and upgrade the upstream hop to TCP.
- Known failure mode: UDP DNS through conntrack can hit a race that drops packets and causes 5-second resolution stalls. Symptoms are random 5 s latency spikes. NodeLocal DNSCache is the standard fix.
- Remember the JVM caches lookups too (see Java DNS Configuration above), so check both layers.
Dual-Stack: Happy Eyeballs
When a host has both A and AAAA records, clients using Happy Eyeballs (RFC 8305) start IPv6 first and, if it has not connected within about 250 ms, race an IPv4 attempt. A broken IPv6 path therefore costs about 250 ms, not a timeout, but only in clients that implement it. Plain socket code may still hang on a dead AAAA address.
Interview Questions
Q1. Describe the full DNS resolution process for api.example.com.
Client checks browser cache β OS cache β if miss, asks local resolver. Resolver checks its cache β if miss, queries root NS for
.comTLD NS β queries TLD NS forexample.comauthoritative NS β queries authoritative NS forapi.example.comβ gets A record (IP + TTL). Resolver caches result and returns to client. Full chain: ~4 queries, 50β200ms. Cached: < 1ms.
Q2. What is a CNAME record and when can't you use it?
A CNAME aliases one hostname to another (the canonical name). The resolver follows the CNAME and looks up the final A/AAAA record. You cannot use CNAME at the zone apex (naked domain:
example.com) because RFC 1034 forbids other records coexisting with a CNAME, and zones must have SOA/NS records. Use ALIAS or ANAME (Route 53, Cloudflare) for apex aliases β they resolve to A records.
Q3. What is DNS TTL and how does it affect deployments?
TTL is how long resolvers and clients cache a DNS answer. Low TTL (60s) allows fast IP changes but increases query load. Before changing IPs (failover, deployment), lower TTL to 60s and wait for the current TTL to expire globally. Then make the change. After traffic shifts, raise TTL again. Ignoring TTL is why "DNS propagation takes 24-48 hours" β high TTLs of existing records.
Q4. What is DNS cache poisoning and how does DNSSEC prevent it?
Cache poisoning: an attacker convinces a resolver to cache a fraudulent DNS mapping (e.g.,
bank.com β attacker's IP). Classically exploited via Kaminsky attack by guessing the transaction ID. DNSSEC prevents this by signing zone data with cryptographic keys β the resolver validates the signature chain from the root. A tampered response has an invalid signature and is rejected.
Q5. What is the difference between a recursive resolver and an authoritative nameserver?
Recursive resolver (e.g., 8.8.8.8): accepts DNS queries from clients, does the work of traversing the hierarchy, caches results. It knows how to find answers but doesn't own any zones. Authoritative nameserver: owns the actual DNS records for a zone (
example.com). It is the final source of truth and doesn't recurse β it just answers questions about its own zones.
Q6. What are SRV records and when are they used?
SRV (Service) records specify the hostname and port for a service:
_service._proto.name TTL class SRV priority weight port target. Used by gRPC (for load balancing and discovery), SIP/VoIP, XMPP, and Kubernetes internal DNS. Example:_grpc._tcp.api.example.com SRV 10 20 443 api-grpc.example.com. Allows clients to discover service endpoints from DNS.
Q7. What is split-horizon DNS?
Split-horizon DNS returns different answers based on the requester's source IP. Internal clients get private IP addresses (routing traffic over the internal network), external clients get public IPs. Uses: keeping internal topology hidden, routing internal traffic without external NAT traversal, geographic load balancing. Implemented via DNS views in BIND or separate internal/external zones in cloud DNS.
Q8. Why might a Java application not respect a DNS TTL change immediately?
Java's JVM has its own DNS cache separate from the OS. By default it caches successful lookups indefinitely (
networkaddress.cache.ttl=-1in some older versions) or for 30 seconds. When DNS TTL expires, the OS and resolver update, but the JVM still serves the old cached IP. Fix: setnetworkaddress.cache.ttlinjava.securityor viaSecurity.setProperty(). HTTP connection pools may also cache connections to specific IPs beyond the DNS TTL.
