Skip to content
/ newdns Public

A library for building custom DNS servers in Go.

License

Notifications You must be signed in to change notification settings

256dpi/newdns

Repository files navigation

newdns

Test GoDoc Release

A library for building custom DNS servers in Go.

The newdns library wraps the widely used, but low-level github.com/miekg/dns package with a simple interface to quickly build custom DNS servers. The implemented server only supports a subset of record types (A, AAAA, CNAME, MX, TXT) and is intended to be used as a leaf authoritative name server only. It supports UDP and TCP as transport protocols and implements EDNS0. Conformance is tested by issuing a corpus of tests against a zone in AWS Route53 and comparing the response and behavior.

The intention of this project is not to build a feature-complete alternative to "managed zone" offerings by major cloud platforms. However, some projects may require frequent synchronization of many records between a custom database and a cloud-hosted "managed zone". In this scenario, a custom DNS server that queries the own database might be a lot simpler to manage and operate. Also, the distributed nature of the DNS system offers interesting qualities that could be leveraged by future applications.

Example

// create zone
zone := &newdns.Zone{
    Name:             "example.com.",
    MasterNameServer: "ns1.hostmaster.com.",
    AllNameServers: []string{
        "ns1.hostmaster.com.",
        "ns2.hostmaster.com.",
        "ns3.hostmaster.com.",
    },
    Handler: func(name string) ([]newdns.Set, error) {
        // return apex records
        if name == "" {
            return []newdns.Set{
                {
                    Name: "example.com.",
                    Type: newdns.A,
                    Records: []newdns.Record{
                        {Address: "1.2.3.4"},
                    },
                },
                {
                    Name: "example.com.",
                    Type: newdns.AAAA,
                    Records: []newdns.Record{
                        {Address: "1:2:3:4::"},
                    },
                },
            }, nil
        }

        // return sub records
        if name == "foo" {
            return []newdns.Set{
                {
                    Name: "foo.example.com.",
                    Type: newdns.CNAME,
                    Records: []newdns.Record{
                        {Address: "bar.example.com."},
                    },
                },
            }, nil
        }

        return nil, nil
    },
}

// create server
server := newdns.NewServer(newdns.Config{
    Handler: func(name string) (*newdns.Zone, error) {
        // check name
        if newdns.InZone("example.com.", name) {
            return zone, nil
        }

        return nil, nil
    },
    Logger: func(e newdns.Event, msg *dns.Msg, err error, reason string) {
        fmt.Println(e, err, reason)
    },
})

// run server
go func() {
    err := server.Run(":1337")
    if err != nil {
        panic(err)
    }
}()

// print info
fmt.Println("Query apex: dig example.com @0.0.0.0 -p 1337")
fmt.Println("Query other: dig foo.example.com @0.0.0.0 -p 1337")

// wait forever
select {}

Credits