A high-performance, asynchronous DNS resolver implemented in Rust using Tokio for concurrent request handling.
This DNS resolver implements a recursive DNS resolution algorithm that queries authoritative name servers to resolve domain names to IP addresses. The resolver starts from root name servers and follows the DNS hierarchy to find the authoritative answer for any given domain.
The Domain Name System (DNS) is a hierarchical distributed naming system that translates human-readable domain names (like example.com) into IP addresses (like 192.0.2.1). Our resolver implements the recursive resolution process:
- Query Reception: The resolver listens on port 2053 for incoming DNS queries from clients
- Recursive Resolution: Starting from root name servers, the resolver follows the DNS hierarchy:
- Queries root name servers (starting with
192.203.230.10) - Follows referrals to authoritative name servers
- Continues until it finds the final answer
- Queries root name servers (starting with
- Response: Returns the resolved IP address to the client
The resolver uses an asynchronous, event-driven architecture built on Tokio:
- Concurrent Request Handling: Each incoming request is handled in a separate async task
- Non-blocking I/O: UDP socket operations are asynchronous, allowing high throughput
- Recursive Algorithm: Implements iterative queries to name servers following DNS referrals
- DNS Packet Parser: Custom implementation for parsing and constructing DNS packets
- Recursive Resolver: Core algorithm that follows DNS hierarchy to resolve queries
- Name Server Fetcher: Handles communication with authoritative name servers
- Async Runtime: Tokio-based async runtime for concurrent request processing
- ✅ Asynchronous request handling using Tokio
- ✅ Recursive DNS resolution following RFC standards
- ✅ Support for A record queries (IPv4 addresses)
- ✅ Root name server bootstrapping
- ✅ Error handling and recovery
- ✅ Concurrent client support
- ✅ Custom DNS packet parsing and construction
- Rust 1.75 or later
- Cargo package manager
# Clone or navigate to the project directory
cd DNSserver
# Build the release version
cargo build --release --bin asyncDnsResolver# Run the built binary
./target/release/asyncDnsResolverThe resolver will start listening on:
- Port 2053: For incoming DNS queries from clients
- Random port: For outgoing queries to name servers
You should see output similar to:
Listening on 127.0.0.1:2053
Bound to 0.0.0.0:43521
You can test the DNS resolver using standard DNS tools:
# Using dig
dig @127.0.0.1 -p 2053 example.com
# Using nslookup
nslookup example.com 127.0.0.1 2053The project includes a Dockerfile for containerized deployment:
# Build the Docker image
docker build -t dns-resolver .
# Run the container
docker run -p 53:53/udp -p 2053:2053/udp dns-resolverThe resolver currently uses these default settings:
- Listen Address:
127.0.0.1:2053 - Root Name Server:
192.203.230.10(a.root-servers.net) - Maximum Resolution Depth: 13 iterations (prevents infinite loops)
- Buffer Size: 4096 bytes for DNS packets
The resolver implements custom parsing for standard DNS packet format:
- Header (12 bytes): Contains flags, question count, answer count, etc.
- Questions: Domain name queries
- Answers: Resolved records
- Authority: Authoritative name server records
- Additional: Additional helpful records
- Parse incoming DNS query packet
- Extract the domain name from the question section
- Start with a root name server IP
- Iteratively query name servers:
- Send query to current name server
- Parse response for either answer or referral
- Follow referrals to more specific name servers
- Stop when authoritative answer is found
- Construct and send response packet back to client
The resolver includes comprehensive error handling for:
- Network connectivity issues
- Malformed DNS packets
- Missing name servers
- Query timeouts
- Buffer overflow protection
- Concurrent Processing: Multiple queries handled simultaneously
- Async I/O: Non-blocking network operations
- Memory Efficient: Fixed-size buffers with bounds checking
- Fast Startup: Minimal dependencies and quick initialization
Current implementation focuses on:
- A record queries (IPv4 addresses) only
- Basic recursive resolution
- UDP transport only
Future enhancements could include:
- AAAA records (IPv6)
- CNAME resolution
- DNS caching
- TCP fallback for large responses
- DNSSEC validation
To contribute to this project:
- Ensure Rust 1.75+ is installed
- Run tests:
cargo test - Format code:
cargo fmt - Check for issues:
cargo clippy
This project is available under standard open source licenses.