← Projects

Authoritative DNS server

A small authoritative DNS server in Go, written from the wire format up without a DNS library, serving a JSON-configured zone over UDP and TCP.

Stack
Go, Docker, GitHub Actions
Source
github.com/ZhuoqunWei/dns-resolver

The goal was a DNS server small enough to explain end to end: every byte of the protocol parsed and encoded by hand, every response code reachable from a test. It’s authoritative only. It deliberately doesn’t do recursive resolution, forwarding, or caching.

The DNS message header: ID; then flags QR, Opcode, AA, TC, RD, RA, Z, and RCODE; then question, answer, authority, and additional record counts. The server sets AA, TC, and RCODE. 0123456789101112131415byte 0byte 2byte 4byte 6byte 8byte 10ID · pairs each reply with its queryQROpcodeAATCRDRAZRCODEQDCOUNT · questionsANCOUNT · answer recordsNSCOUNT · authority recordsARCOUNT · additional records, including EDNS OPTWritten by the server in every reply: authoritative answer (AA), truncation (TC), response code (RCODE)
Where it starts. Every DNS message opens with this 12-byte header. The server reads it bit by bit and writes its own, without a DNS library.

What it implements

Area Behavior
Wire format Headers, flags, QNAME, QTYPE/QCLASS, resource records, EDNS OPT
Zone data Validated JSON config with A, AAAA, SOA, and multi-record RRsets
Authority Authoritative answers, NXDOMAIN, NODATA, REFUSED, negative SOA records
UDP 512-byte classic responses, EDNS negotiation up to 1232 bytes, whole-record truncation
TCP Length-prefixed framing, concurrent clients, connection reuse, read/write deadlines
Lifecycle Graceful shutdown on SIGINT/SIGTERM, static non-root container image
Decision flow. A query arrives over UDP or TCP. If the name is outside the server's zones the reply is REFUSED. If the name does not exist, NXDOMAIN with an SOA record. If no records of the requested type exist, NODATA with an SOA record. Over UDP, if the answer is larger than 512 bytes, or up to 1232 with EDNS, whole records are dropped and the TC bit is set so the client retries over TCP. Otherwise the authoritative answer is sent. Query arrives over UDP or TCPIn a zone this server owns?yesnoREFUSEDnot authoritative for the nameDoes the name exist?yesnoNXDOMAINSOA in the authority sectionRecords of the requested type?yesnoNODATANOERROR, empty answer, SOA in authorityOver UDP: does it fit?512 bytes, or up to 1232 with EDNSyesnoTruncated replyTC bit set, client retries over TCPSend the authoritative answer
From query to reply. Each query walks the same checks in order. A UDP answer that won't fit drops whole records, never half of one, and sets TC so the client asks again over TCP.

Measured

queries per second, median of three trials at 30,000 offered
29,944
queries lost
0
median p99 latency bound
3.0 ms
statement coverage across 130 test cases, race detector on
87.2%

Benchmarks ran on Apple M3 Pro loopback on October 27, 2026. They’re local baselines, not production or network-wide throughput. Raw logs are in the repository.