Open-Source Wikis

/

CoreDNS

/

Reference

/

Data models

coredns/coredns

Data models

Internal types you'll encounter when writing or reading plugin code. All types are in the coredns/coredns module unless noted.

request.Request

The per-request abstraction passed through plugins. Defined in request/request.go:

type Request struct {
    Req *dns.Msg
    W   dns.ResponseWriter
    // unexported caches: zone, name, do, size, family, ...
}

Useful methods:

Method Returns
r.Name() qname (lower-cased, dotted)
r.QName() qname as in the message
r.Type() qtype as a string ("A", "AAAA")
r.QType() qtype as uint16
r.Class() qclass as a string ("IN", "CH")
r.QClass() qclass as uint16
r.Family() 1 for IPv4 client, 2 for IPv6
r.Proto() "udp" / "tcp" / "https" / etc.
r.Do() Was the DNSSEC OK bit set?
r.Size() Client's advertised UDP buffer
r.IP() Client IP as a string
r.Port() Client port
r.RemoteAddr() net.Addr for the client
r.LocalAddr() net.Addr for the server
r.Zone() Zone match against Zones
r.SizeAndDo(*dns.Msg) Set OPT on a response based on request
r.Scrub(*dns.Msg) Truncate response to fit client's buffer
r.Match(*dns.Msg) Does this response satisfy this request?

Request is the canonical way to inspect a query. Plugins should rarely poke into r.Req directly.

dnsserver.Server

The server type that Caddy starts. Defined in core/dnsserver/server.go:

type Server struct {
    Addr         string
    server       [2]*dns.Server                // udp, tcp
    m            sync.Mutex
    zones        map[string][]*Config
    dnsWg        sync.WaitGroup
    graceTimeout time.Duration
    trace        trace.Trace
    debug        bool
    stacktrace   bool
    classChaos   bool
    tsigSecret   map[string]string
    metaCollector []metadata.Collector
}

There are six Server* variants (Server, ServerTLS, ServerHTTPS, ServerHTTPS3, ServerQUIC, ServergRPC), each with its own *.go file. They all embed or compose this base struct.

Key methods:

  • NewServer(addr, group) — build the chain from Config.Plugin.
  • ServeDNS(ctx, w, r) — entry point for incoming queries. Wraps with recover(), classifies, normalizes, dispatches into the chain.
  • Listen() / ListenPacket() — return the listener. Each transport overrides these.
  • Serve(l) / ServePacket(p) — drive the dns.Server loops.
  • Stop() — graceful shutdown.

dnsserver.Config

Per-server-block configuration. Plugins write into this in their setup functions. See Configuration → Internal config struct for the full field listing. The shape:

type Config struct {
    Zone                 string
    Transport            string
    ListenHosts          []string
    Port                 string
    Root                 string
    Debug                bool
    // ...timeouts
    TLSConfig            *tls.Config
    // ...max-counts for each encrypted server type
    NumSockets           int
    ProxyProtoConnPolicy proxyproto.PolicyFunc
    Plugin               []plugin.Plugin
    View                 View
    // ...registry helpers (FirstConfigInBlock, AllPlugins, ...)
}

Config is built by dnsserver.NewConfig per server block. Setup functions get a *caddy.Controller whose c.ServerBlockConfigs[i] walks back to Config.

plugin.Handler and plugin.Plugin

From plugin/plugin.go:

type Handler interface {
    ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error)
    Name() string
}

type Plugin func(Handler) Handler

Plugin is a "wrapper": given the next handler in the chain, return a new handler that does its work and then calls Next. Handler is the runtime interface. The register.go file in core/dnsserver/ chains them:

stack := plugin.Handler(emptyHandler)
for i := len(plugins) - 1; i >= 0; i-- {
    stack = plugins[i](stack)
}

plugin.Backend (interface that backends implement)

In plugin/backend.go:

type ServiceBackend interface {
    Services(ctx context.Context, state request.Request, exact bool, opt Options) ([]msg.Service, error)
    Reverse(ctx context.Context, state request.Request, exact bool, opt Options) ([]msg.Service, error)
    Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error)
    Records(ctx context.Context, state request.Request, exact bool) ([]msg.Service, error)
    IsNameError(err error) bool
    Serial(state request.Request) uint32
    MinTTL(state request.Request) uint32
    Transfer(ctx context.Context, state request.Request) (uint32, <-chan []dns.RR, error)
}

etcd, kubernetes, route53, clouddns, nomad, azure all implement this. The shared plugin.Backend helper produces a generic Handler from a ServiceBackend.

etcd/msg.Service

From plugin/etcd/msg/service.go:

type Service struct {
    Host     string
    Port     int
    Priority int
    Weight   int
    Text     string
    Mail     bool
    TTL      uint32
    TargetStrip int
    Group    string
    Key      string
}

A Service is the lingua franca of backend plugins. Each backend converts its native records into Service instances; the shared backend helper converts those into dns.RR for the response. This is why the etcd and route53 plugins look so similar at the boundary.

dns.Msg, dns.RR, dns.ResponseWriter

These come from github.com/miekg/dns. The most important methods/fields:

  • dns.Msg.Question[0].Name, .Qtype, .Qclass — the question.
  • dns.Msg.Answer, .Ns, .Extra — answer/authority/additional.
  • dns.Msg.Rcode, .MsgHdr.Authoritative, .RecursionAvailable, .Truncated, .AuthenticatedData, .CheckingDisabled — header bits.
  • dns.Msg.IsEdns0() — get the OPT record if any.
  • dns.ResponseWriter.WriteMsg(m) — send a reply.
  • dns.ResponseWriter.RemoteAddr(), .LocalAddr() — addresses.

Most plugins do not poke into dns.Msg directly — they use request.Request instead.

metadata.Collector / metadata.Provider

In plugin/metadata/metadata.go:

type Collector interface {
    Collect(ctx context.Context, state request.Request) context.Context
}

type Provider interface {
    Metadata(ctx context.Context, state request.Request) context.Context
}

Plugins that populate metadata implement Provider. The metadata plugin is itself a Collector: it iterates registered providers and asks each to add values via metadata.SetValueFunc(ctx, key, fn). Consumers read with metadata.ValueFunc(ctx, key)().

plugin.Readiness

type Readiness interface {
    Ready() bool
}

kubernetes, forward, health, ready, etcd implement this. The ready plugin walks its registered list and returns 200 only when every check passes.

plugin.Transferer

type Transferer interface {
    Transfer(zone string, serial uint32) (<-chan []dns.RR, error)
}

The transfer plugin implements this and exposes outgoing AXFR/IXFR. file, secondary, and auto provide the actual zone data.

ResponseWriter wrappers

Several plugins wrap the response writer to mutate the reply:

  • request.ScrubWriter — truncates to fit the EDNS0 buffer size.
  • dnstest.Recorder — captures for tests.
  • plugin/cache.ResponseWriter — clones the message into the cache before forwarding.
  • plugin/dnssec.ResponseWriter — signs the answer on the way out.
  • plugin/header.ResponseWriter — flips header bits.
  • plugin/loadbalance.RoundRobinResponseWriter — rotates A/AAAA records.
  • plugin/minimal.MinimalResponseWriter — strips additional/authority sections.

The pattern: implement dns.ResponseWriter, embed the upstream writer, override WriteMsg, and forward.

pluginWriter

In core/dnsserver/server.go. Tracks which plugin in the chain produced the response (the one that called WriteMsg) so the metrics plugin can label responses_total{plugin="..."}. See Plugin system → Plugin attribution for metrics.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Data models – CoreDNS wiki | Factory