An iterative DNS resolver that walks the delegation chain starting at the root servers, builds DNS packets by hand, and parses responses without using socket.getaddrinfo, dnspython, or libc resolver hooks. Built to showcase low-level networking, bit-level packet work, and careful data-structure choices that FAANG interviewers love to see.
- Fully manual DNS wire-format encoder/decoder (RFC 1035) including compression pointers.
- Real iterative resolution: follows NS referrals from roots → TLDs → authoritative servers.
- TTL-aware in-memory cache to avoid redundant queries.
- Zero dependencies; everything is standard library for portability and inspection.
git clone https://github.com/mohosy/dns-resolver-from-scratch.git
cd dns-resolver-from-scratch
PYTHONPATH=. python3 -m src.cli example.com --traceExample trace (recorded Jan 24, 2026):
[query] example.com A @ 198.41.0.4
[query] example.com A @ 192.41.162.30
[query] example.com A @ 108.162.192.162
[answer] ['example.com 300s A 104.18.27.120', 'example.com 300s A 104.18.26.120'] (ttl=300)
---
example.com 300s A 104.18.27.120
example.com 300s A 104.18.26.120
src/message.py— DNS header/question/RR dataclasses plus wire-format encoding & decoding (handles name compression, multiple record types, and TTL parsing).src/resolver.py— Iterative resolver that walks delegations, retries on timeouts, resolves glue when missing, and exposes a simpleresolve()API.src/cache.py— TTL-aware hash map (dictionary) to memoize recent answers; chosen because O(1) lookups map perfectly to DNS query keys.src/servers.py— Static root server list for deterministic bootstrapping.src/cli.py— Minimal CLI with trace option for debugging the delegation path.
Data structure callouts:
- Hash map cache: O(1) keyed by
(name, type)with TTL eviction. DNS traffic is bursty; constant-time lookups keep latency down and avoid over-querying upstreams. - Lists for traversal order: We prepend newly discovered NS glue IPs to explore depth-first along a delegation chain, mirroring how resolvers chase referrals quickly.
# Basic A record
PYTHONPATH=. python3 -m src.cli example.com
# AAAA record with trace
PYTHONPATH=. python3 -m src.cli cloudflare.com --type AAAA --tracePYTHONPATH=. python3 -m unittest discover -s tests -p 'test*.py'- Add EDNS0 + larger UDP payload support and TCP fallback for truncated responses.
- Expand record parsing (MX, TXT) and negative caching (NXDOMAIN with SOA MINIMUM).
- Optional JSON output for automation.