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 fromConfig.Plugin.ServeDNS(ctx, w, r)— entry point for incoming queries. Wraps withrecover(), 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) HandlerPlugin 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.