A lightweight DNS forwarder written in Go.
It listens for DNS queries, forwards them to an upstream resolver (e.g. 9.9.9.9), and sends the responses back to the client.
Designed for learning how DNS works at the packet level — parsing headers, handling compression pointers, and building real network logic from scratch.
- Parses and builds DNS headers manually (bit-fields, flags, etc.)
- Handles domain name compression (
0xC0pointer format) - Forwards queries to upstream servers (
9.9.9.9:53) - Non-blocking UDP handling using goroutines
- Simple logging for requests and responses
Goal: reduce upstream lookups and improve response speed.
- Implement an in-memory cache using
sync.Mapor LRU. - Cache key:
(QNAME, QTYPE, QCLASS, DO-bit). - Respect DNS TTLs: store expiry timestamp and auto-expire entries.
- Rewrite transaction ID when serving cached responses.
- Add optional persistent cache (Ideally redis?)
Goal: block unwanted or malicious domains.
- Load a list of domains from file or URL (
blocklist.txt). - Match on full domain or suffix (e.g.
ads.google.com,*.tracking.net). - Return a synthetic A record (
0.0.0.0) or NXDOMAIN instead of forwarding. - Cache blocked responses with infinite TTL.
Goal: log or route queries based on the client’s location.
- Integrate MaxMind GeoLite2 using
oschwald/geoip2-golang. - Log query source country / city.
- Maintain a metrics log for per-country query counts.
Goal: define custom static records for specific domains.
- Load mappings from a simple
hosts.jsonor/etc/hostsstyle file:{ "my.local.dev": "192.168.1.50", "printer.lan": "192.168.1.200" } - When a matching QNAME is found, bypass upstream and reply locally.
- Cache local overrides as permanent records.
- Support multiple upstream resolvers with round-robin or fallback logic.
- Return
SERVFAILwhen upstream times out. - Implement
EDNS(0)and support larger UDP payloads. - Graceful shutdown and metrics summary on exit.
- Command-line flags:
--listen :8053--upstream 9.9.9.9:53,1.1.1.1:53--cache-ttl 300s--geoip-db ./GeoLite2-City.mmdb
ristretto Simple DNS Client by Alan Mislove Create a TCP and UDP Client and Server using Go (Video) Bitwise Operators by Alex Hyett RFC1035 RFC2782
MIT — free to study, hack, and extend.