coredns/coredns
Request and response
Active contributors: miekg, chrisohaver, johnbelamaric
Purpose
Plugins receive raw *dns.Msg and dns.ResponseWriter from miekg/dns. The request package wraps both with a higher-level Request type that caches commonly-needed values and a ScrubWriter that ensures every reply fits the client's advertised buffer.
Directory layout
request/
├── request.go # Request struct and accessors
├── request_test.go
├── writer.go # ScrubWriter
├── writer_test.go
├── edns0.go # supportedOptions filter
└── edns0_test.gorequest.Request
Request carries the response writer, the message, an optional zone, and a small cache so repeated calls to Name(), IP(), Size(), Do() don't repeat work.
Common accessors:
| Method | Returns |
|---|---|
Name() / QName() |
Lowercase / unmodified question name (with trailing dot) |
Type() / QType() |
Question type (string and uint16) |
Class() / QClass() |
Question class |
IP() / Port() / Family() |
Client address bits |
LocalIP() / LocalPort() / LocalAddr() |
Server-side address |
Proto() |
"udp" or "tcp" |
Size() |
Effective UDP buffer size (after EDNS0 + normalization) |
Do() |
True if the DO bit (DNSSEC OK) is set |
Match(reply) |
True if a reply matches the question |
Scrub(reply) |
Truncate / compress reply to fit Size() |
NewWithQuestion(name, typ) returns a copy of the request with a different question — useful for plugins like cache that want to look up CNAME targets without mutating the original message.
Clear() invalidates the caches; cache calls this before reusing a Request for a prefetch.
EDNS0 / DO / SizeAndDo
Request.Size() consults the OPT record on the request:
size := uint16(0)
if o := r.Req.IsEdns0(); o != nil {
r.do = o.Do()
size = o.UDPSize()
}
size = edns.Size(r.Proto(), size)edns.Size normalises a few corner cases — TCP always returns dns.MaxMsgSize, UDP enforces a minimum and a global maximum (both configurable via the bufsize plugin which sets OPT.UDPSize on the question itself).
SizeAndDo(m) ensures the reply has an OPT record that mirrors the request's intent. If the reply already has an OPT, the bits are normalized; otherwise the request's OPT is reused. Supported options are filtered by supportedOptions in edns0.go (NSID, EDNS-padding, COOKIE, EDE, etc.).
ScrubWriter
The DNS server installs ScrubWriter (request.NewScrubWriter) before the plugin chain runs:
w = request.NewScrubWriter(r, w)ScrubWriter is a thin wrapper that overrides WriteMsg to call Request.Scrub(reply) first. Scrub truncates the message until it fits Size(), trying without compression first and then with compression. UDP messages over the IPv4 (1480) or IPv6 (1220) fragmentation thresholds are compressed even if they would otherwise fit, to avoid IP fragmentation. The TC bit is set on truncated UDP messages so clients retry over TCP.
This is why plugins can write dns.Msg instances of arbitrary size without worrying about UDP buffer math — the scrub layer handles it once, at the boundary.
Response classification
A second piece — plugin/pkg/response — classifies replies by content. response.Typify(msg, now) returns one of:
NoError— answer set is non-empty and matches the question.NameError— NXDOMAIN.NoData— NOERROR with empty answer.Delegation— referral.OtherError,Meta,Update,ServerError— used by the cache to decide what not to cache.
The cache plugin uses response.Typify to choose between positive and negative caches and to decide when to skip caching entirely.
Key abstractions
| Symbol | File | Description |
|---|---|---|
Request |
request/request.go |
The wrapped client query |
ScrubWriter |
request/writer.go |
Response writer that scrubs to fit the buffer |
supportedOptions |
request/edns0.go |
EDNS0 option allowlist for replies |
Type (in plugin/pkg/response) |
plugin/pkg/response/typify.go |
Reply classification used by cache, dnssec, errors |
Integration points
Server.ServeDNSwraps every reply withScrubWriter. Plugins do not need to install it themselves.plugin/cacheconstructs its ownRequestto look up cache keys (Name,Type,Class, DO/CD bits) and synthesises prefetch requests using a synthetic*net.TCPAddrso the response budget defaults to TCP sizes.plugin/forward,plugin/grpc,plugin/dns64,plugin/rewriteall consumeRequestfor routing and rewriting.plugin/pkg/ednsis shared with this package; the OPT record handling is intentionally split so plugins can calledns.Version(r)directly.
Entry points for modification
- New cached field on
Request→ add a private field plus an accessor that lazily fills it (mirrorRequest.IP()). - New EDNS0 option supported in replies → extend
supportedOptionsinrequest/edns0.go. - New compression / truncation policy →
Request.Scrubinrequest/request.go. - New reply classification →
plugin/pkg/response.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.