coredns/coredns
Forwarding and caching
Active contributors: johnbelamaric, miekg, chrisohaver, Tantalor93, rdrozhdzh
Purpose
This group covers plugins that send queries elsewhere or short-circuit them locally. Together they make CoreDNS a recursive-style resolver in front of upstreams.
Plugins in this group
| Plugin | Source | One-liner |
|---|---|---|
forward |
plugin/forward/ |
Forward to upstream resolvers over UDP, TCP, or DoT |
grpc |
plugin/grpc/ |
Forward to upstream over gRPC (pb/dns.proto) |
cache |
plugin/cache/ |
LRU cache for positive and negative responses |
dns64 |
plugin/dns64/ |
RFC 6147 IPv6 synthesis from IPv4 answers |
loop |
plugin/loop/ |
Detect forwarding loops at startup |
How they cooperate
graph LR
Q[query] --> Cache[cache]
Cache -->|miss| Forward[forward]
Cache -->|hit| Reply[reply]
Forward --> U1[upstream 1]
Forward --> U2[upstream 2]
U1 -->|response| Cache
U2 -->|response| Cache
Cache -->|stored| Replycache lives in front of forward (or any backend) and stores positive (success) and denial (denial) replies in two sharded caches. forward opens persistent connections to one or more upstreams, picks one according to a policy (random, round-robin, sequential), and writes the reply through the cache wrapper so future queries hit.
forward
The cornerstone forwarder.
- Multiple upstreams (max 15) randomized on first use, with round-robin and sequential policies.
- Persistent connection cache per upstream (default
expire 10s); idle TCP/UDP/DoT connections live inplugin/pkg/proxy. - Inband health checking: when a query fails,
upruns. IN NSagainst the upstream every 500 ms until it answers; queries continue with healthy peers in the meantime.max_fails(default 2) controls how many consecutive failures mark an upstream down. - DoT (
tls://...) supported including per-endpoint server name (tls://9.9.9.9%dns.quad9.net). - Knobs:
force_tcp,prefer_udp,expire,max_idle_conns,max_fails,max_concurrent,max_connect_attempts,next(rcode list to fall through),failover(rcodes to retry on next upstream),failfast_all_unhealthy_upstreams,health_check. - Dnstap integration: when the
dnstapplugin is loaded, every upstream exchange is reported. - Metrics: latency histograms, request counters, connection cache size, upstream selection counters (
plugin/forward/metrics.go).
Forward.ServeDNS walks the upstream list, retries up to defaultTimeout (5s) or max_connect_attempts, and falls through on next rcodes. The full lifecycle is in plugin/forward/forward.go.
grpc
Sibling of forward that speaks the gRPC service from pb/dns.proto. Same connection cache, same policies; useful for cluster-internal CoreDNS-to-CoreDNS forwarding where TLS+gRPC is preferred over DoT.
cache
A two-cache plugin: positive replies (success) and denials (denial) live in separate sharded LRUs. Sharding factor is 256 by default; default capacity is 9984 entries.
Key behavior:
- TTLs are clamped between configurable
minandmaxper cache. Defaults: success 5s..3600s, denial 5s..1800s. - The plugin wraps the downstream
dns.ResponseWriterwith its ownResponseWriterso it can callres.Copy()and store before forwarding to the client. prefetch AMOUNT [DURATION] [PERCENTAGE%]refreshes popular entries before they expire by replaying the question through the chain with a synthetic TCP-styleRemoteAddr. Prefetch responses go throughnewPrefetchResponseWriterwhich short-circuits the actual client write.serve_stale [DURATION] [REFRESH_MODE]keeps expired entries usable while a refresh runs (RFC 8767).verifymode only writes the new entry when the refresh succeeds (verifyStaleResponseWriter).keepttlpreserves the original TTL of cached records when serving them.servfail DURATIONenables a brief negative cache for SERVFAIL replies to dampen storms.- DNSSEC-aware: DO/CD bits are part of the cache key (see
key()inplugin/cache/cache.go). - Metrics: hits, misses, drops, size, evictions, prefetches, served stale (
plugin/cache/metrics.go).
The cache lookup path is in plugin/cache/handler.go; the writer path that stores entries is in plugin/cache/cache.go.
dns64
RFC 6147 IPv6 synthesis. When a client asks for AAAA and gets NODATA, dns64 re-issues the question as A and synthesises AAAA records inside a configurable IPv6 prefix (64:ff9b::/96 by default). The plugin uses plugin/pkg/upstream to look up the A record through the rest of the chain.
loop
Sends a probe at startup to detect short forwarding loops (a CoreDNS that forwards to itself). Logs and aborts startup if a loop is found. No runtime cost after startup.
Cross-plugin notes
cacheshould always come beforeforwardso cached replies don't pay the forwarding cost.forwardandgrpcboth report throughdnstapif thednstapplugin is loaded.- Connection caching in
plugin/pkg/proxyis shared betweenforwardandgrpc. forwardhonoursmetadataset by upstream plugins;metadata.SetValueFunc("forward/upstream", ...)lets downstream consumers know which upstream answered.dns64cooperates withcacheonly when the synthesized answer's TTL is non-zero.
Key source files
| File | Purpose |
|---|---|
plugin/forward/forward.go, setup.go, policy.go, dnstap.go, metrics.go |
The forwarder |
plugin/grpc/grpc.go, setup.go |
gRPC forwarder |
plugin/cache/cache.go, handler.go, setup.go, item.go, metrics.go |
Caching layer |
plugin/cache/freq/ |
Frequency tracker for prefetch |
plugin/dns64/dns64.go |
IPv6 synthesis |
plugin/loop/loop.go |
Loop probe |
plugin/pkg/proxy/ |
Shared upstream connection cache |
plugin/pkg/up/ |
Periodic probes for forward health |
Related pages
- Backends — where the forwarded query might originate before forwarding.
- Observability —
dnstap,prometheus,log,errorsfor tracking forwards and cache. - Transports — DoT, DoQ, gRPC server side.
- Shared packages —
pkg/proxy,pkg/up,pkg/cache.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.