How to write a DNS server in Go

Here’s a DNS server written in Go. It uses the package, which is an alternative to the standard library’s DNS stuff, and also lets you implement a DNS server rather than just a client. The example DNS server below only knows how to answer A queries, and for these, it only knows the IP addresses of two domains.

package main

import (

var domainsToAddresses map[string]string = map[string]string{
	"": "",
	"": "",

type handler struct{}
func (this *handler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	msg := dns.Msg{}
	switch r.Question[0].Qtype {
	case dns.TypeA:
		msg.Authoritative = true
		domain := msg.Question[0].Name
		address, ok := domainsToAddresses[domain]
		if ok {
			msg.Answer = append(msg.Answer, &dns.A{
				Hdr: dns.RR_Header{ Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60 },
				A: net.ParseIP(address),

func main() {
	srv := &dns.Server{Addr: ":" + strconv.Itoa(53), Net: "udp"}
	srv.Handler = &handler{}
	if err := srv.ListenAndServe(); err != nil {
		log.Fatalf("Failed to set udp listener %s\n", err.Error())

Example usage:

$ sudo go run main.go &
$ dig @

; <<>> DiG 9.8.3-P1 <<>> @
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25014
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;		IN	A


;; Query time: 0 msec
;; WHEN: Sun Aug 27 00:27:06 2017
;; MSG SIZE  rcvd: 66

This program could be extended with more custom logic. For example, at Pusher (the company I work for), we could operate a DNS server which resolves a Pusher app’s domain to the cluster that the app is on.

Tagged .

Similar posts

More by Jim

Want to build a fantastic product using LLMs? I work at Granola where we're building the future IDE for knowledge work. Come and work with us! Read more or get in touch!

This page copyright James Fisher 2017. Content is not associated with my employer. Found an error? Edit this page.