A full recursive DNS resolver implementation in Rust using tokio for asynchronous I/O. Starts resolution from root servers and follows the DNS hierarchy down to authoritative servers.
- Full Recursive Resolution: Queries root servers, follows NS referrals through TLD and authoritative servers
- Complete DNS Protocol: Implements RFC 1035 with support for A, AAAA, CNAME, MX, TXT, NS, SOA, and PTR records
- Glue Record Handling: Properly extracts IP addresses from additional sections
- Out-of-Bailiwick Resolution: Recursively resolves nameservers when glue records aren't provided
- CNAME Following: Automatically follows CNAME chains to final answers
- Dual Protocol: Handles both UDP (primary) and TCP (for large responses)
- High Performance: Built with tokio for efficient concurrent request handling
- Smart Caching: LRU cache with TTL respect and negative caching
- Security: Transaction ID randomization, loop detection, input validation
- Observability: Structured logging with tracing
Unlike forwarding DNS servers that delegate to upstream resolvers, this resolver implements the full iterative resolution process:
- Start with queries to root servers (a-m.root-servers.net)
- Follow NS referrals to TLD servers (.com, .org, etc.)
- Continue following referrals to authoritative servers
- Cache results at each level for performance
cargo run
The server will start on 0.0.0.0:5454
by default.
Edit config.toml
to customize settings:
[server]
bind_address = "0.0.0.0:5454"
[cache]
max_size = 10000
# Run all tests
cargo test
# Test with dig
dig @127.0.0.1 -p 5454 example.com
# See the resolution path
RUST_LOG=debug cargo run
# Then query to see it walk from root → TLD → authoritative
Benchmarked on Apple Silicon (M-series):
Operation | Time | Notes |
---|---|---|
Parse simple query | 226 ns | RFC 1035 message parsing |
Parse deep domain | 544 ns | a.b.c.d.e.f.example.com |
Serialize response (5 answers) | 720 ns | With compression |
Cache get (hit) | 303 ns | LRU cache lookup |
Cache get (miss) | 64 ns | Fast negative lookup |
Full cycle (10 answers) | 3.98 µs | Parse + serialize |
Full cycle (50 answers) | 17.2 µs | Large response handling |
Run performance benchmarks using Criterion:
# Run all benchmarks
cargo bench
# Run specific benchmark group
cargo bench parse
cargo bench cache
# View detailed HTML reports with graphs
open target/criterion/report/index.html
Benchmarks cover:
- DNS message parsing (simple and complex domains)
- DNS message serialization
- Cache operations (put, get hit/miss, LRU eviction)
- Different message sizes (1-50 answers)
- Multiple query types (A, AAAA, CNAME, MX, TXT, NS)
- Domain name compression
Client Query
↓
Cache Check
↓ (miss)
Root Servers (a-m.root-servers.net)
↓ (NS referral)
TLD Servers (.com servers)
↓ (NS referral)
Authoritative Servers (example.com servers)
↓ (answer)
Cache & Return