Skip to content

abb3rrant/Simple-DNS-Server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tiny DNS Server in Go

A minimal, educational DNS server implemented from scratch in Go. It parses DNS queries, handles basic A-record lookups from an in-memory map, and sends DNS responses over UDP.

This is meant for learning: the code is heavily commented to explain what each piece is doing and why.

Features

  • Parses DNS header, names (with compression), and questions
  • Answers A (IPv4) queries for a small in-memory zone
  • Sends valid DNS responses over UDP
  • Clear, well-documented code paths for parsing and serialization

Limitations (by design)

  • Listens on UDP port 5353 instead of 53 (no admin rights required)
  • Only answers Type A, Class IN
  • No EDNS(0), DNSSEC, TCP fallback, or name compression on serialization
  • Very small in-memory zone (edit zoneA in main.go)

Project structure

  • dns.go — Core DNS types (Header, Question, ResourceRecord, Message)
  • parse.go — Safe readers, header parsing, name parsing (with compression), question parsing, message parsing
  • serialize.go — Big-endian writers, name encoder (no compression), message serialization, response helpers
  • main.go — UDP server loop, minimal query handler, in-memory zone, and response builder

Run

Use Go to build and run the server. It listens on UDP :5353.

# From the project root
go run .

You should see:

DNS server listening on :5353

Query it

nslookup example.com 127.0.0.1:5353
nslookup localhost 127.0.0.1:5353
dig @127.0.0.1 -p 5353 example.com A
dig @127.0.0.1 -p 5353 localhost A

Expected responses (default zone):

  • example.com93.184.216.34
  • localhost127.0.0.1
  • Unknown names → NXDOMAIN

Customize the zone

Edit the in-memory zone in main.go:

var zoneA = map[string]string{
    "example.com": "93.184.216.34",
    "localhost":   "127.0.0.1",
    // add more here
}

Keys are case-insensitive at query time. Trailing dots are ignored when matching.

How it works (high level)

  • Parsing follows RFC 1035: fixed 12-byte header, then question/answer sections.
  • Names on the wire are label sequences; compression pointers are supported when parsing.
  • Serialization writes header + sections back to bytes (big-endian). For simplicity, we do not compress names when sending.
  • Response flags set QR=1, copy OPCODE and RD from the query, set AA, and set RCODE appropriately.

Troubleshooting

  • Nothing returns: ensure you’re querying port 5353, not 53.
  • Permission denied on port 53: use 5353 or run with elevated privileges (not recommended for learning).
  • NXDOMAIN for known name: check you added it to zoneA, and you queried A (IPv4) records.
  • Mixed case or trailing dot: server normalizes lookups; try dig @127.0.0.1 -p 5353 ExAmPlE.CoM. A.

Next steps

  • Add AAAA (IPv6), CNAME, NS records
  • Implement name compression during serialization
  • Add unit tests for parsing/serialization helpers
  • Add a config or file-backed zone loader

Have fun exploring DNS internals! This server aims to be a clear, hackable starting point rather than production-ready.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages