A lightweight DNS forwarder written in Go that implements a recursive DNS resolver with local caching.
The resolver listens for DNS queries over UDP, checks a local cache for existing records, and forwards unresolved queries to an upstream DNS server. Responses from the upstream server are cached based on their TTL before being returned to the client.
This project was built primarily as a learning exercise to better understand:
- DNS message encoding and decoding
- UDP networking in Go
- Recursive DNS resolution
- DNS caching
- Resource Record parsing
- RFC 1035
- UDP DNS server
- DNS packet parser
- DNS packet encoder
- Recursive forwarding to upstream DNS server
- Local in-memory cache
- TTL-based cache expiration
- Supports multiple DNS questions in a single query
- Parses DNS headers, questions, answers, authority, and additional sections
- Logging for incoming queries and cache operations
- Client sends a DNS query.
- Resolver parses the DNS packet.
- Resolver checks whether the requested records exist in cache.
- If all requested records exist:
- Respond immediately from cache.
- Otherwise:
- Forward unresolved questions to an upstream DNS server.
- Parse the upstream response.
- Cache all cacheable Resource Records.
- Return the completed DNS response to the client.
Clone the repository
git clone https://github.com/mk-milly02/dns-forwarder.git
cd dns-forwarderRun
go run ./cmd/main.go -p xxxx -dThe server listens on
127.0.0.100:xxxx
Example query
dig @127.0.0.100 -p 2026 google.com +noednsThe resolver maintains an in-memory cache indexed by:
<Record Type>-<Domain Name>
Example:
A-google.com
AAAA-google.com
MX-google.com
Each cached entry stores:
- Resource Record
- TTL
- Expiration time
Expired records are automatically removed by a background cleanup routine.
A DNS message consists of:
+----------------------+
| Header |
+----------------------+
| Question |
+----------------------+
| Answer |
+----------------------+
| Authority |
+----------------------+
| Additional |
+----------------------+
Client
|
| Query: A example.com
|
Resolver
|
| Cache miss
|
Forward to 8.8.8.8
|
Receive Response
|
Cache Answer
|
Return Response
Subsequent requests for example.com are served directly from cache until the TTL expires.
Implemented
- UDP server
- DNS message parsing
- DNS message serialization
- Recursive forwarding
- DNS cache
- TTL expiration
- Multiple-question handling
Planned
- TCP fallback
- DNSSEC & EDNS support
- Negative caching
- LRU cache eviction
- Metrics endpoint
- Configuration file
- Integration tests
- Docker support
- RFC 1035 - Domain Names - Implementation and Specification
- RFC 1034 - Domain Names - Concepts and Facilities
- https://codingchallenges.fyi/challenges/challenge-dns-forwarder
MIT

