Skip to content
Thomas Mangin edited this page Aug 16, 2026 · 1 revision

Pre-Alpha. This page describes behavior that may change.

Ze is on both sides of DNS. It asks, through a built-in caching resolver every component shares, and it answers, through two authoritative plugins that sit on one server harness. The two sides share no configuration and no cache.

Side Surface Config root
Ze asking Built-in stub resolver with an LRU cache, plus the | resolve and | origin pipes system { name-server ... }, system { dns { ... } }
Ze answering AS112 node, and GeoDNS per-source-IP answers service { as112 { ... } }, service { geodns { ... } }

Authoritative answer shape

Both authoritative plugins hand their reply to one harness, which owns the answer shape, the opcode check, the transport size bound, and the single write to the wire. No answer path can change any of it.

Property Value Source
Recursion available never set Ze is authoritative-only
Authoritative (AA) set, except on a Refused reply RFC 1035 Section 4.1.1
Reserved Z field zero RFC 1035 Section 4.1.1
Authenticated data (AD) zero RFC 4035 Section 3.1.6: Ze verifies nothing
Name compression off, except on a datagram reply the harness has to shorten

A query whose opcode is not a standard query (inverse query, server status request, notify, update) draws Not Implemented before any zone lookup runs, so an opcode Ze does not serve costs one header. RFC 1035 Section 6.4 requires that answer of every name server that does not support inverse queries. Ze serves standard queries only, so every other opcode draws the same reply. Without the check they fall through to the answer path, where a name inside a served zone draws a normal answer and a name outside one draws NXDOMAIN, and both claim Ze acted on a request it never implemented.

A reply on a datagram transport is bounded and gets TC when it is shortened. The bound is 512 octets (RFC 1035 Section 2.3.4) or the larger reassembly buffer the requestor advertised in an OPT record (RFC 6891 Section 6.2.3). An advertisement below 512 does not lower the bound, so a requestor cannot shrink a reply below what Section 2.3.4 already allows. A reply on TCP, DoT or DoH is written whole and never carries TC: RFC 1035 Section 4.2.1 bounds UDP only, and Section 4.2.2 puts no length ceiling on a stream.

A query that panics mid-answer is recovered by the harness, logged, and dropped with no reply written. One bad query cannot crash the listener.

Answer policy

Both plugins pick from three answers, and the same rule decides which.

Query RCODE Authority section
Name under no zone this node serves 5 Refused (RFC 1035 Section 4.1.1), AA clear empty
Name inside a served zone that the zone does not own 3 Name Error zone SOA
Name the zone owns, asked for a type it holds no record of 0 No Error, empty Answer zone SOA

The two negative answers carry the zone SOA because RFC 2308 Section 3 requires it of an authoritative server "when reporting an NXDOMAIN or indicating that no data of the requested type exists", so a resolver can cache the answer.

Existence is a property of the zone, never of the client. GeoDNS chooses a host set by client source prefix, so a host configured in one set and not another has data for one client and none for another. Both get No Error with an empty Answer, not a name error. The name set is built once per config generation from every configured host plus every interior node above one: a config holding only a.b.example.com. gives b.example.com. existence too, as the node the leaf hangs from (RFC 1035 Section 3.1).

Zone matching runs over DNS labels, never over characters. The name evilexample.com. ends with every character of the zone example.com. while its label sequence does not nest inside it, so it is refused rather than answered.

GeoDNS

service { geodns { ... } } serves small zones whose answer depends on where the client is. A source list maps a client prefix to a named host-set, longest prefix wins, and 0.0.0.0/0 or ::/0 is the catch-all.

service {
    geodns {
        enabled true
        listener v4 {
            ip 127.0.0.1
            port 5300
        }
        listener v6 {
            ip ::1
            port 5300
        }
        default-ttl 300
        client-ip-source edns0-then-packet
        zone geodns.example.
        nameserver 82.219.4.22
        soa {
            contact hostmaster
            serial-mode auto-epoch
        }
        host-set internal {
            host proxy.geodns.example. {
                address 10.0.0.1
            }
        }
        host-set external {
            host proxy.geodns.example. {
                address 10.0.0.2
            }
        }
        source 82.219.0.0/16 {
            host-set internal
        }
        source 0.0.0.0/0 {
            host-set external
        }
    }
}
Leaf Default Notes
enabled false Enable the GeoDNS server.
listener <name> 127.0.0.1:5300 and ::1:5300 UDP and TCP endpoint. Repeat with one entry per family for a dual-stack pair. Port conflicts across services are caught at config time.
zone (empty) Zones served, as FQDNs. A query name must be one of these or a name inside one, compared label by label.
nameserver (empty) Nameserver IPv4 addresses. ns1..nsN.<zone> A glue is synthesized, up to 9.
client-ip-source edns0-then-packet edns0 uses only the RFC 7871 client-subnet option and answers nothing without it, packet uses the UDP/TCP source IP, edns0-then-packet prefers the option and falls back.
default-ttl 300 Record TTL when a host omits its own, 1 to 2147483647 (RFC 2181 Section 8). Zero is not allowed.
soa Synthesized SOA. serial-mode is auto-epoch (default), auto-datetime (YYYYMMDDnn, RFC 1912) or fixed. contact defaults to hostmaster, and mname to ns1.<first-zone>. GeoDNS serves no AXFR.
host-set <name> Reusable set of host records, each with addresses or SRV fields.
source <prefix> Maps a client prefix to a host set.
tls / doh off DNS-over-TLS (RFC 7858) and DNS-over-HTTPS (RFC 8484) listeners, same answer policy as cleartext.

show geodns reports enabled state, bind addresses and port, client-IP source mode, zones, nameserver / host-set / source counts, and the current SOA serial.

The configured TTL reaches the wire as configured. It is not floored against the zone SOA MINIMUM: RFC 1035 Section 3.3.13 asked for that floor and RFC 2308 Section 4 withdraws it, calling it deprecated and never used in practice.

Built-in resolver

The resolver serves every Ze component that needs a name looked up. It is built on github.com/miekg/dns and caches with an O(1) LRU.

system {
    name-server [8.8.8.8 1.1.1.1]
    dns {
        resolv-conf-path /tmp/resolv.conf
        timeout 5
        cache-size 10000
        cache-ttl 86400
    }
}
Option Default Notes
name-server (none) Static upstream servers. The first is used by the internal resolver; all are written to resolv.conf.
resolv-conf-path /tmp/resolv.conf Suits gokrazy's read-only rootfs. Empty disables writing.
timeout 5 Query timeout in seconds, 1 to 60.
cache-size 10000 Maximum cached entries. 0 disables caching.
cache-ttl 86400 Maximum cache TTL in seconds. 0 uses the response TTL only.

With no configured server the resolver falls back to /etc/resolv.conf; when that is missing or empty, queries fail closed with no DNS server configured. Static servers take priority over DHCP-discovered ones. Resolver settings apply at startup, so changing them needs a process restart.

Cache inspection and clearing:

show dns cache stats
show dns cache list
show dns cache record example.com

clear dns cache
clear dns cache stats
clear dns cache record example.com
clear dns cache record example.com type AAAA

Two pipes enrich the JSON output of any command with a DNS lookup per IP address value: | resolve adds a <key>-name PTR hostname (500ms per lookup), and | origin adds <key>-asn, <key>-as-name and <key>-prefix from Team Cymru (2s).

See also

  • AS112 for the anycast sink node and its BGP origination.
  • CLI for the pipe operators the resolver feeds.
  • Plugins for as112 and geodns in the plugin catalogue.

Adapted from main/docs/features/dns-resolver.md and main/docs/architecture/dns/.

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally