GoatNS Logo

Yet another authoritative DNS name server. But with goat references.


  • DNS over HTTPS (RFC8484) on /dns-query
  • Web API/UI for management
    • OIDC Authentication to the Web UI
    • Token auth for API endpoints


Look at zones.json and goatns.example.json for examples.

The configuration file's fields are best found here: https://goatns.dotgoat.net/rustdoc/goatns/config/struct.ConfigFile.html. Note that the ip_allow_list field is a nested map.

Running in Docker

There's a docker container at ghcr.io/yaleman/goatns:latest and a docker-compose.yml file in the repository if that's your thing.


Found a bug, want to change something, the sky is falling? Create an issue!.

Wondering how something works, need a chat, or are curious there's so many goat references? Discussions are great for that.

Built in Rust

Thanks to some great packages:

Rust Crate Documentation

Auto-generated and available here: https://yaleman.github.io/goatns/rustdoc/goatns


Rust tests are run using cargo.

cargo test

A handy load testing tool is dnsblast. This'll run 50,000 "valid" queries, 1500 packets per second, to port 15353:

./dnsblast 50000 1500 15353

Or if you want to fuzz the server and test that it doesn't blow up:

./dnsblast fuzz 50000 1500 15353

Supported request/record types

This list is now in the book.

Additional thanks


I'll totally forget to update this, so check the rustdoc for ConfigFile for up-to-date information.

To write out a "default" config file, run goatns --export-default-config which will dump the contents of the system defaults.

User Authentication

This is build for Kanidm but should work with any OIDC identity provider.

User auto-provisioning

This is disabled by default, but set user_auto_provisioning to true and anyone who can authenticate will be able to add themselves to the system.

Admin contact

If it's configured, this'll show up in a few places.

  • the home page
  • error messages
  • randomly because I forgot to update the docs

These are the current supported formats:

Contact TypeExample Format

Packet Header

These things are spicy.

Processing Packets

UDP Flow

    participant udpport as UDP Port
    participant udpserver as udp_server
    participant parsequery as parse_query
    participant datastore as Data Store
    udpport->>udpserver: Connect on port 15353
    udpserver->>parsequery: Parse all the bytes into a Result Object
    parsequery->>datastore: Command::Get for name/type
    datastore->>parsequery: Respond with data
    parsequery->>udpserver: Return Result Object
    udpserver->>udpport: Send data to client

Supported request/record types

  • A (1) RFC1035
  • AAAA (28) RFC3596
  • AFSDB (18) RFC1183
  • APL (42) RFC3123 (Experimental)
  • AXFR (252) RFC1035
    • add an allow-list in the config file (CIDRs)
  • ANY (255) RFC8482
    • should check for zones, is currently just YOLOing a response to any request
    • return a HINFO record of "RFC8482", can't be stored
  • CAA (257) RFC6844
  • CDNSKEY (60) RFC7344 Child copy of DNSKEY record, for transfer to parent
  • CDNSKEY (59) RFC7344 Child copy of DS record, for transfer to parent
  • CERT (37) RFC4398 Certificate record
  • CSYNC (62) RFC7477 Specify a synchronization mechanism between a child and a parent DNS zone. Typical example is declaring the same NS records in the parent and the child zone
  • CNAME (5) RFC7477
  • DHCID (49) RFC4701 Used in conjunction with the FQDN option to DHCP
  • DLV (32769) RFC4431 DNSSEC Lookaside Validation record
  • DNAME (39) RFC6672 Delegation name record
  • DNSKEY (48) RFC4034 DNS Key record The key record used in DNSSEC.
  • EUI48 (108) RFC7043 MAC address (EUI-48) A 48-bit IEEE Extended Unique Identifier.
  • EUI64 (109) RFC7043 MAC address (EUI-64) A 64-bit IEEE Extended Unique Identifier.
  • HINFO (13) RFC8482 Providing Minimal-Sized Responses to DNS Queries That Have QTYPE=ANY
    • RFC1035 interpretation is done
    • Check up on the details in RFC8482 - "Unobsoleted by RFC 8482."
  • HIP (55) RFC8005 Host Identity Protocol Method of separating the end-point identifier and locator roles of IP addresses.
  • HTTPS (65) (IETF Draft)[https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/00/?include_text=1] HTTPS Binding RR that improves performance for clients that need to resolve many resources to access a domain. More info in this IETF Draft by DNSOP Working group and Akamai technologies.
  • IPSECKEY (45) RFC4025 IPsec Key Key record that can be used with IPsec
  • KX (36) RFC2230 Key Exchanger record Used with some cryptographic systems (not including DNSSEC) to identify a key management agent for the associated domain-name. Note that this has nothing to do with DNS Security. It is Informational status, rather than being on the IETF standards-track. It has always had limited deployment, but is still in use.
  • LOC (29) RFC1876 Location record
  • MX (15) RFC1035 and RFC7505 Mail exchange record
  • NAPTR (35) RFC3403 Naming Authority Pointer Allows regular-expression-based rewriting of domain names which can then be used as URIs, further domain names to lookups, etc.
  • NS
  • NSEC (47) RFC4034 Next Secure record Part of DNSSEC—used to prove a name does not exist. Uses the same format as the (obsolete) NXT record.
  • NSEC3 50 RFC5155 Next Secure record version 3 An extension to DNSSEC that allows proof of nonexistence for a name without permitting zonewalking
  • NSEC3PARAM 51 RFC5155 NSEC3 parameters Parameter record for use with NSEC3
  • OPENPGPKEY 61 RFC7929 OpenPGP public key record A DNS-based Authentication of Named Entities (DANE) method for publishing and locating OpenPGP public keys in DNS for a specific email address using an OPENPGPKEY DNS resource record.
  • OPT 41 RFC6891 Option This is a pseudo-record type needed to support EDNS.
  • PTR 12 RFC1035
  • RRSIG 46 RFC4034 DNSSEC signature Signature for a DNSSEC-secured record set. Uses the same format as the SIG record.
  • RP 17 RFC1183 Responsible Person Information about the responsible person(s) for the domain. Usually an email address with the @ replaced by a .
  • SMIMEA 53 RFC8162 S/MIME cert association Associates an S/MIME certificate with a domain name for sender authentication.
  • SOA (6) RFC1035 and RFC2308 Start of [a zone of] authority record
  • SRV (33) RFC2782 Service locator
  • SSHFP (44) RFC4255 SSH Public Key Fingerprint Resource record for publishing SSH public host key fingerprints in the DNS, in order to aid in verifying the authenticity of the host. RFC6594 defines ECC SSH keys and SHA-256 hashes. See the IANA SSHFP RR parameters registry for details
  • SVCB 64 IETF Draft Service Binding RR that improves performance for clients that need to resolve many resources to access a domain. More info in this IETF Draft by DNSOP Working group and Akamai technologies.
  • TA 32768 — DNSSEC Trust Authorities Part of a deployment proposal for DNSSEC without a signed DNS root. See the IANA database and Weiler Spec for details. Uses the same format as the DS record.
  • TKEY 249 RFC2930 Transaction Key record A method of providing keying material to be used with TSIG that is encrypted under the public key in an accompanying KEY RR.
  • TLSA 52 RFC6698 TLSA certificate association A record for DANE.
  • TSIG 250 RFC2845 Transaction Signature Can be used to authenticate dynamic updates as coming from an approved client, or to authenticate responses as coming from an approved recursive name server
  • TXT 16 RFC1035 Text record
  • URI 256 RFC7553 Uniform Resource Identifier
  • ZONEMD (63) RFC8976 Message Digests for DNS Zones Provides a cryptographic message digest over DNS zone data at rest.

A lot of the details above were transcribed from the Wikipedia page on DNS REcord Types


Record Types

OpenTelemetry config

At the moment this isn't great but it works.

Running jaeger locally on docker (from the quickstart docs)

docker run --rm -it --name jaeger \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 14250:14250 \
  -p 14268:14268 \
  -p 14269:14269 \
  -p 9411:9411 \

Example environment variables:

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" #grpc
export OTEL_SERVICE_NAME="goatns"
export OTEL_LOG_LEVEL="debug"
export OTEL_TRACES_SAMPLER="always_on"