Files
dns/man/coredns-forward.7
41febf8d0a chore: sync upstream 2026-03-27 (#1)
* Bump version to 1.14.2 (#7895)

This PR bumps version to 1.14.2, as part of the release.

Related to 7883

Signed-off-by: Yong Tang <[email protected]>

* plugin/reload: Allow disabling jitter with 0s (#7896)

This PR fixes #7894 by allowing reload 2s 0s as documented.

Signed-off-by: Yong Tang <[email protected]>

* Bump golang to 1.26.1 (#7902)

* Update release note for upcoming 1.14.2 (#7897)

* fix: release date for v1.14.2 notes (#7906)

Updated release date for CoreDNS 1.14.2 to match the actual release
date. This causes issues when rendering the coredns.io website.

Signed-off-by: Ville Vesilehto <[email protected]>

* chore(lint): bump golangci-lint to v2.11.1 (#7905)

- Added nolint to plugin/auto/walk.go to avoid a symlink/TOCTOU
  warning, as it needs to follow symlink.
- Replaced a few flagged integer conversions with safe equivalents in
  cache hashing, reuseport socket setup, and TLS arg handling
- Preallocated response rule slices in plugin/rewrite/name.go
- Replaced WriteString(fmt.Sprintf/Sprintln(...)) with direct
  fmt.Fprint* calls
- Removed stale nolint directives from code and tests that are no
  longer needed

Signed-off-by: Ville Vesilehto <[email protected]>

* feat(secondary): Send NOTIFY messages after zone transfer (#7901)

* feat(secondary): Send NOTIFY messages after zone transfer

- Modified TransferIn() method to accept a transfer.Transfer parameter
- Added NOTIFY message sending after successful zone transfer in secondary plugin
- Updated Update() method to pass the transfer handler through the zone update cycle
- Added comprehensive tests for the secondary notify functionality

Closes #5669

Signed-off-by: liucongran <[email protected]>

* fix(secondary): Fix TransferIn method call in test

Update test to pass nil parameter to TransferIn method after signature change

Signed-off-by: liucongran <[email protected]>

* refactor(secondary): Clean up imports and add helper methods

- Reorder imports for consistency
- Add hasSOA() and getSOA() helper methods to Zone
- Remove unnecessary blank lines in tests

Signed-off-by: liucongran <[email protected]>

* fix(test): Fix variable declaration in secondary test

Change corefile variable assignment to use short declaration syntax (:=)
to fix compilation error.

Signed-off-by: liucongran <[email protected]>

* refactor(secondary): Use getSOA helper method in shouldTransfer

Replace direct SOA access with getSOA() helper method for consistency.

Signed-off-by: liucongran <[email protected]>

---------

Signed-off-by: liucongran <[email protected]>
Co-authored-by: liucongran <[email protected]>

* build(deps): bump github/codeql-action from 4.32.5 to 4.32.6 (#7911)

* build(deps): bump docker/login-action from 3.7.0 to 4.0.0 (#7908)

* build(deps): bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#7909)

* build(deps): bump github.com/aws/aws-sdk-go-v2/service/secretsmanager (#7920)

* build(deps): bump google.golang.org/grpc from 1.79.1 to 1.79.2 (#7916)

* build(deps): bump aquasecurity/trivy-action from 0.34.1 to 0.35.0 (#7910)

* build(deps): bump k8s.io/klog/v2 in the k8s-io group (#7912)

* build(deps): bump golang.org/x/sys from 0.41.0 to 0.42.0 (#7913)

Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/sys/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* build(deps): bump sigs.k8s.io/mcs-api from 0.3.0 to 0.4.0 (#7919)

Bumps [sigs.k8s.io/mcs-api](https://github.com/kubernetes-sigs/mcs-api) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/kubernetes-sigs/mcs-api/releases)
- [Changelog](https://github.com/kubernetes-sigs/mcs-api/blob/master/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/mcs-api/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/mcs-api
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* build(deps): bump github.com/aws/aws-sdk-go-v2/service/route53 (#7917)

Bumps [github.com/aws/aws-sdk-go-v2/service/route53](https://github.com/aws/aws-sdk-go-v2) from 1.62.2 to 1.62.3.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/fsx/v1.62.2...service/fsx/v1.62.3)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/route53
  dependency-version: 1.62.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* plugin/forward: add max_age option to enforce an absolute connection lifetime (#7903)

* plugin/pkg/proxy: add max_age for per-connection lifetime cap

Introduce a max_age setting on Transport that closes connections based
on creation time, independent of idle-timeout (expire).

Background: PR #7790 changed the connection pool from LIFO to FIFO for
source-port diversity. Under FIFO, every connection is cycled through
the pool and its used timestamp is refreshed continuously. When request
rate is high enough that pool_size / request_rate < expire, no
connection ever becomes idle and expire never fires. This prevents
CoreDNS from opening new connections to upstreams that scale out (e.g.
new Kubernetes pods behind a ClusterIP service with conntrack pinning).

max_age addresses this by enforcing an absolute upper bound on
connection lifetime regardless of activity:
- persistConn gains a created field set at dial time.
- Transport gains maxAge (default 0 = unlimited, preserving existing
  behaviour).
- Dial(): rejects cached connections whose creation age exceeds max_age.
- cleanup(): when maxAge > 0, uses a linear scan over both idle-timeout
  and max-age predicates; when maxAge == 0, preserves the original
  binary-search path on used time (sorted by FIFO insertion order).
- Both hot paths pre-compute the deadline outside any inner loop to
  avoid repeated time.Now() calls.

Tests added:
- TestMaxAgeExpireByCreation: connection with old created but fresh used
  must be rejected even though idle-timeout would pass.
- TestMaxAgeFIFORotation: three FIFO-rotated connections (old created,
  fresh used) must all be rejected, confirming that continuous rotation
  cannot prevent max-age expiry.

Signed-off-by: cangming <[email protected]>

* plugin/forward: add max_age option

Expose Transport.SetMaxAge through the forward plugin so operators can
set an absolute upper bound on connection lifetime via the Corefile.

Usage:
  forward . 1.2.3.4 {
      max_age 30s
  }

Default is 0 (unlimited), which preserves existing behaviour.
A positive value causes connections older than max_age to be closed and
re-dialled on the next request, ensuring CoreDNS reconnects to newly
scaled-out upstream pods even under sustained load where the idle
timeout (expire) would never fire.

If max_age is set, it must not be less than expire; the parser rejects
this combination at startup with a clear error message.

Signed-off-by: cangming <[email protected]>

---------

Signed-off-by: cangming <[email protected]>

* build(deps): bump github.com/aws/aws-sdk-go-v2/feature/ec2/imds (#7914)

* build(deps): bump github.com/aws/aws-sdk-go-v2/config (#7915)

* Add optional TLS support to /metrics endpoint (#7255)

* Use exporter-toolkit to enable optional TLS encryption on /metrics endpoint

Signed-off-by: peppi-lotta <[email protected]>

* Implement startup listener to signal server readiness

Signed-off-by: peppi-lotta <[email protected]>

---------

Signed-off-by: peppi-lotta <[email protected]>

* refactor(test): replace deprecated pbutil dep (#7924)

Replace github.com/matttproud/golang_protobuf_extensions/pbutil
with google.golang.org/protobuf/encoding/protodelim for reading
varint size-delimited protobuf messages in the metrics scraper.

The new protodelim package is already available via the existing
google.golang.org/protobuf dependency, so this removes pbutil as
a direct dependency entirely.

Signed-off-by: Ville Vesilehto <[email protected]>

* Fix case-sensitive zone handling in the transfer plugin for AXFR/IXFR. (#7899)

This PR fixes Fix case-sensitive zone handling in the transfer plugin for AXFR/IXFR, raised in 7898

Signed-off-by: Yong Tang <[email protected]>

* core: Propagate TSIG secrets to DoT server (#7928)

* build(deps): bump github/codeql-action from 4.32.6 to 4.33.0 (#7929)

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.6 to 4.33.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/0d579ffd059c29b07949a3cce3983f0780820c98...b1bff81932f5cdfc8695c7752dcee935dcd061c8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1 (#7930)

Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 2.6.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/a06a81a03ee405af7f2048a818ed3f03bbf83c7b...153bb8e04406b158c6c84fc1615b65b24149a1fe)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* core: Avoid spawning waiter goroutines when QUIC worker pool is full (#7927)

* build(deps): bump golang.org/x/crypto from 0.48.0 to 0.49.0 (#7939)

* build(deps): bump github.com/aws/aws-sdk-go-v2 from 1.41.3 to 1.41.4 (#7938)

* build(deps): bump golang.org/x/net from 0.51.0 to 0.52.0 (#7936)

* build(deps): bump google.golang.org/api from 0.269.0 to 0.271.0 (#7933)

* build(deps): bump github.com/aws/aws-sdk-go-v2/config (#7932)

* build(deps): bump github.com/aws/aws-sdk-go-v2/service/route53 (#7937)

* fix(file): protect Zone.Expired with mutex (#7940)

* build(deps): bump github.com/aws/aws-sdk-go-v2/service/secretsmanager (#7935)

* docs(cache): clarify TTL directive (#7941)

* core: Reject oversized GET dns query parameter of DoH (#7926)

* core: Reject oversized GET dns query parameter of DoH

The DoH POST path limits request size using http.MaxBytesReader(..., 65536), but the GET path passes the dns query value directly to base64ToMsg() with no equivalent bound.

This PR adds length check.

Signed-off-by: Yong Tang <[email protected]>

* Fix

Signed-off-by: Yong Tang <[email protected]>

---------

Signed-off-by: Yong Tang <[email protected]>

* build(deps): bump google.golang.org/grpc from 1.79.2 to 1.79.3 (#7945)

* Core: Propagate TSIG status in DoQ transport (#7947)

This PR nsure DoQ writer preserves and returns TSIG verification status, preventing authentication bypass on DNS-over-QUIC.

Signed-off-by: Yong Tang <[email protected]>

* Update github workflow to release windows builds in zip format. (#7946)

* feat: Add GitHub Actions workflow for drafting releases and update Makefile to build Windows releases as zip archives.

Signed-off-by: John-Michael Mulesa <[email protected]>

* Generate both tgz and zip for Windows to support any existing workflows.

Signed-off-by: John-Michael Mulesa <[email protected]>

---------

Signed-off-by: John-Michael Mulesa <[email protected]>

* build(deps): bump github/codeql-action from 4.33.0 to 4.34.1 (#7952)

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.33.0 to 4.34.1.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b1bff81932f5cdfc8695c7752dcee935dcd061c8...38697555549f1db7851b81482ff19f1fa5c4fedc)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.34.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* build(deps): bump github.com/DataDog/dd-trace-go/v2 from 2.6.0 to 2.7.0 (#7955)

Bumps [github.com/DataDog/dd-trace-go/v2](https://github.com/DataDog/dd-trace-go) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/DataDog/dd-trace-go/releases)
- [Commits](https://github.com/DataDog/dd-trace-go/compare/v2.6.0...v2.7.0)

---
updated-dependencies:
- dependency-name: github.com/DataDog/dd-trace-go/v2
  dependency-version: 2.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* ci: use go-version-file instead of GITHUB_ENV (#7958)

* ci(docker): scope secrets to publish step only (#7959)

* ci(yamllint): replace third-party action with uvx (#7957)

* build(deps): bump the k8s-io group with 3 updates (#7953)

* build(deps): bump the go-etcd-io group with 2 updates (#7954)

* ci(dependabot): add 7-day cooldown for updates (#7960)

* fix(kubernetes): record cluster_ip services in dns_programming_duration metric (#7951)

Signed-off-by: Azeez Syed <[email protected]>

* plugin/cache: prefetch without holding a client connection (#7944)

* ci: add persist-credentials: false to checkouts (#7964)

* ci(release): use env vars for expressions in shell (#7965)

* ci(depsreview): add version comment to pin (#7966)

* plugin/transfter: Fix longestMatch to select the most specific zone correctly. (#7949)

* plugin/transfter: Fix longestMatch to select the most specific zone correctly.

This PR Fix longestMatch to select the most specific zone correctly.The previous implementation used lexicographic string comparison, which could choose the wrong zone; this change selects the longest matching zone instead.

Signed-off-by: Yong Tang <[email protected]>

* Tie breaker

Signed-off-by: Yong Tang <[email protected]>

* Fix

Signed-off-by: Yong Tang <[email protected]>

---------

Signed-off-by: Yong Tang <[email protected]>

* core: Preserve TSIG status in gRPC transport (#7943)

* ci: remove trivy-action (#7961)

* feat: add support for running CoreDNS as a Windows service (#7962)

* feat: add support for running CoreDNS as a Windows service

Signed-off-by: John-Michael Mulesa <[email protected]>

* Use non-deprecated service check function.

Signed-off-by: John-Michael Mulesa <[email protected]>

* refactor: remove deprecated build tags and clean up imports in service files

Signed-off-by: John-Michael Mulesa <[email protected]>

* ci: add Windows test workflow and fix log field access in service_windows.go

Signed-off-by: John-Michael Mulesa <[email protected]>

* test: implement cross-platform file permission restriction for Windows compatibility in run_test.go

Signed-off-by: John-Michael Mulesa <[email protected]>

* refactor: remove Windows-specific icacls test logic and restrict unreadable file test to non-Windows platforms

Signed-off-by: John-Michael Mulesa <[email protected]>

* docs: add documentation for -windows-service flag in man page

Signed-off-by: John-Michael Mulesa <[email protected]>

---------

Signed-off-by: John-Michael Mulesa <[email protected]>

* test(dnssec): fix err in TestZoneSigningDouble (#7969)

* chore(docs): regenerate man pages (#7971)

* chore(docs): update Docker build command in README (#7972)

* plugin/tsig: add require_opcode directive for opcode-based TSIG (#7828)

Extend the tsig plugin to require TSIG signatures based on DNS opcodes,
similar to the existing qtype-based requirement.

The new require_opcode directive accepts opcode names (QUERY, IQUERY,
STATUS, NOTIFY, UPDATE) or the special values "all" and "none".

This is useful for requiring TSIG on dynamic update (UPDATE) or zone
transfer notification (NOTIFY) requests while allowing unsigned queries.

Example:
```
  tsig {
    secret key. NoTCJU+DMqFWywaPyxSijrDEA/eC3nK0xi3AMEZuPVk=
    require_opcode UPDATE NOTIFY
  }
```

Signed-off-by: Seena Fallah <[email protected]>

* plugin/tls: Add the keylog option to configure TLSConfig.KeyLogWriter (#7537)

* tls: Add the keylog option to configure TLSConfig.KeyLogWriter

Signed-off-by: Ilya Kulakov <[email protected]>

* tls: Close keylog file on instance shutdown.

Signed-off-by: Ilya Kulakov <[email protected]>

---------

Signed-off-by: Ilya Kulakov <[email protected]>

---------

Signed-off-by: Yong Tang <[email protected]>
Signed-off-by: Ville Vesilehto <[email protected]>
Signed-off-by: liucongran <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Signed-off-by: cangming <[email protected]>
Signed-off-by: peppi-lotta <[email protected]>
Signed-off-by: John-Michael Mulesa <[email protected]>
Signed-off-by: Azeez Syed <[email protected]>
Signed-off-by: Seena Fallah <[email protected]>
Signed-off-by: Ilya Kulakov <[email protected]>
Co-authored-by: Yong Tang <[email protected]>
Co-authored-by: Ville Vesilehto <[email protected]>
Co-authored-by: liucongran <[email protected]>
Co-authored-by: liucongran <[email protected]>

Co-authored-by: cangming <[email protected]>
Co-authored-by: Peppi-Lotta <[email protected]>
Co-authored-by: John-Michael Mulesa <[email protected]>
Co-authored-by: Syed Azeez <[email protected]>

Co-authored-by: John-Michael Mulesa <[email protected]>
Co-authored-by: Seena Fallah <[email protected]>
Co-authored-by: Ilya Kulakov <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-05-29 21:07:33 -07:00

464 lines
14 KiB
Plaintext

.\" Generated by Mmark Markdown Processer - mmark.miek.nl
.TH "COREDNS-FORWARD" 7 "March 2026" "CoreDNS" "CoreDNS Plugins"
.SH "NAME"
.PP
\fIforward\fP - facilitates proxying DNS messages to upstream resolvers.
.SH "DESCRIPTION"
.PP
The \fIforward\fP plugin re-uses already opened sockets to the upstreams. It supports UDP, TCP and
DNS-over-TLS and uses in band health checking.
.PP
When it detects an error a health check is performed. This checks runs in a loop, performing each
check at a \fI0.5s\fP interval for as long as the upstream reports unhealthy. Once healthy we stop
health checking (until the next error). The health checks use a recursive DNS query (\fB\fC. IN NS\fR)
to get upstream health. Any response that is not a network error (REFUSED, NOTIMPL, SERVFAIL, etc)
is taken as a healthy upstream. The health check uses the same protocol as specified in \fBTO\fP. If
\fB\fCmax_fails\fR is set to 0, no checking is performed and upstreams will always be considered healthy.
.PP
When \fIall\fP upstreams are down it assumes health checking as a mechanism has failed and will try to
connect to a random upstream (which may or may not work).
.SH "SYNTAX"
.PP
In its most basic form, a simple forwarder uses this syntax:
.PP
.RS
.nf
forward FROM TO...
.fi
.RE
.IP \(bu 4
\fBFROM\fP is the base domain to match for the request to be forwarded. Domains using CIDR notation
that expand to multiple reverse zones are not fully supported; only the first expanded zone is used.
.IP \(bu 4
\fBTO...\fP are the destination endpoints to forward to. The \fBTO\fP syntax allows you to specify
a protocol, \fB\fCtls://9.9.9.9\fR or \fB\fCdns://\fR (or no protocol) for plain DNS. The number of upstreams is
limited to 15.
.PP
Multiple upstreams are randomized (see \fB\fCpolicy\fR) on first use. When a healthy proxy returns an error
during the exchange the next upstream in the list is tried.
.PP
Extra knobs are available with an expanded syntax:
.PP
.RS
.nf
forward FROM TO... {
except IGNORED\_NAMES...
force\_tcp
prefer\_udp
expire DURATION
max\_idle\_conns INTEGER
max\_fails INTEGER
max\_connect\_attempts INTEGER
tls CERT KEY CA
tls\_servername NAME
policy random|round\_robin|sequential
health\_check DURATION [no\_rec] [domain FQDN]
max\_concurrent MAX
next RCODE\_1 [RCODE\_2] [RCODE\_3...]
failfast\_all\_unhealthy\_upstreams
failover RCODE\_1 [RCODE\_2] [RCODE\_3...]
}
.fi
.RE
.IP \(bu 4
\fBFROM\fP and \fBTO...\fP as above.
.IP \(bu 4
\fBIGNORED_NAMES\fP in \fB\fCexcept\fR is a space-separated list of domains to exclude from forwarding.
Requests that match none of these names will be passed through.
.IP \(bu 4
\fB\fCforce_tcp\fR, use TCP even when the request comes in over UDP.
.IP \(bu 4
\fB\fCprefer_udp\fR, try first using UDP even when the request comes in over TCP. If response is truncated
(TC flag set in response) then do another attempt over TCP. In case if both \fB\fCforce_tcp\fR and
\fB\fCprefer_udp\fR options specified the \fB\fCforce_tcp\fR takes precedence.
.IP \(bu 4
\fB\fCmax_fails\fR is the number of subsequent failed health checks that are needed before considering
an upstream to be down. If 0, the upstream will never be marked as down (nor health checked).
Default is 2.
.IP \(bu 4
\fB\fCmax_connect_attempts\fR caps the total number of upstream connect attempts
performed for a single incoming DNS request. Default value of 0 means no per-request
cap.
.IP \(bu 4
\fB\fCexpire\fR \fBDURATION\fP, expire (cached) connections after this time, the default is 10s.
.IP \(bu 4
\fB\fCmax_idle_conns\fR \fBINTEGER\fP, maximum number of idle connections to cache per upstream for reuse.
Default is 0, which means unlimited.
.IP \(bu 4
\fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCA\fP define the TLS properties for TLS connection. From 0 to 3 arguments can be
provided with the meaning as described below
.RS
.IP \(en 4
\fB\fCtls\fR - no client authentication is used, and the system CAs are used to verify the server certificate
.IP \(en 4
\fB\fCtls\fR \fBCA\fP - no client authentication is used, and the file CA is used to verify the server certificate
.IP \(en 4
\fB\fCtls\fR \fBCERT\fP \fBKEY\fP - client authentication is used with the specified cert/key pair.
The server certificate is verified with the system CAs
.IP \(en 4
\fB\fCtls\fR \fBCERT\fP \fBKEY\fP \fBCA\fP - client authentication is used with the specified cert/key pair.
The server certificate is verified using the specified CA file
.RE
.IP \(bu 4
\fB\fCtls_servername\fR \fBNAME\fP allows you to set a server name in the TLS configuration; for instance 9.9.9.9
needs this to be set to \fB\fCdns.quad9.net\fR. Using TLS forwarding but not setting \fB\fCtls_servername\fR results in anyone
being able to man-in-the-middle your connection to the DNS server you are forwarding to. Because of this,
it is strongly recommended to set this value when using TLS forwarding.
.PP
Per destination endpoint TLS server name indication is possible in the form of \fB\fCtls://9.9.9.9%dns.quad9.net\fR.
\fB\fCtls_servername\fR must not be specified when using per destination endpoint TLS server name indication
as it would introduce clash between the server name indication spectifications. If destination endpoint
is to be reached via a port other than 853 then the port must be appended to the end of the destination
endpoint specifier. In case of port 10853, the above string would be: \fB\fCtls://9.9.9.9%dns.quad9.net:10853\fR.
.IP \(bu 4
\fB\fCpolicy\fR specifies the policy to use for selecting upstream servers. The default is \fB\fCrandom\fR.
.RS
.IP \(en 4
\fB\fCrandom\fR is a policy that implements random upstream selection.
.IP \(en 4
\fB\fCround_robin\fR is a policy that selects hosts based on round robin ordering.
.IP \(en 4
\fB\fCsequential\fR is a policy that selects hosts based on sequential ordering.
.RE
.IP \(bu 4
\fB\fChealth_check\fR configure the behaviour of health checking of the upstream servers
.RS
.IP \(en 4
\fB\fC<duration>\fR - use a different duration for health checking, the default duration is 0.5s.
.IP \(en 4
\fB\fCno_rec\fR - optional argument that sets the RecursionDesired-flag of the dns-query used in health checking to \fB\fCfalse\fR.
The flag is default \fB\fCtrue\fR.
.IP \(en 4
\fB\fCdomain FQDN\fR - set the domain name used for health checks to \fBFQDN\fP.
If not configured, the domain name used for health checks is \fB\fC.\fR.
.RE
.IP \(bu 4
\fB\fCmax_concurrent\fR \fBMAX\fP will limit the number of concurrent queries to \fBMAX\fP. Any new query that would
raise the number of concurrent queries above the \fBMAX\fP will result in a REFUSED response. This
response does not count as a health failure. When choosing a value for \fBMAX\fP, pick a number
at least greater than the expected \fIupstream query rate\fP * \fIlatency\fP of the upstream servers.
As an upper bound for \fBMAX\fP, consider that each concurrent query will use about 2kb of memory.
.IP \(bu 4
\fB\fCnext\fR If the \fB\fCRCODE\fR (i.e. \fB\fCNXDOMAIN\fR) is returned by the remote then execute the next plugin. If no next plugin is defined, or the next plugin is not a \fB\fCforward\fR plugin, this setting is ignored
.IP \(bu 4
\fB\fCfailfast_all_unhealthy_upstreams\fR - determines the handling of requests when all upstream servers are unhealthy and unresponsive to health checks. Enabling this option will immediately return SERVFAIL responses for all requests. By default, requests are sent to a random upstream.
.IP \(bu 4
\fB\fCfailover\fR - By default when a DNS lookup fails to return a DNS response (e.g. timeout), \fIforward\fP will attempt a lookup on the next upstream server. The \fB\fCfailover\fR option will make \fIforward\fP do the same for any response with a response code matching an \fB\fCRCODE\fR ( e.g. \fB\fCSERVFAIL\fR、\fB\fCREFUSED\fR). \fB\fCNOERROR\fR cannot be used. If all upstreams have been tried, the response from the last attempt is returned.
.PP
Also note the TLS config is "global" for the whole forwarding proxy if you need a different
\fB\fCtls_servername\fR for different upstreams you're out of luck.
.PP
On each endpoint, the timeouts for communication are set as follows:
.IP \(bu 4
The dial timeout by default is 30s, and can decrease automatically down to 1s based on early results.
.IP \(bu 4
The read timeout is static at 2s.
.SH "METADATA"
.PP
The forward plugin will publish the following metadata, if the \fImetadata\fP
plugin is also enabled:
.IP \(bu 4
\fB\fCforward/upstream\fR: the upstream used to forward the request
.SH "METRICS"
.PP
If monitoring is enabled (via the \fIprometheus\fP plugin) then the following metric are exported:
.IP \(bu 4
\fB\fCcoredns_forward_healthcheck_broken_total{}\fR - count of when all upstreams are unhealthy,
and we are randomly (this always uses the \fB\fCrandom\fR policy) spraying to an upstream.
.IP \(bu 4
\fB\fCcoredns_forward_max_concurrent_rejects_total{}\fR - count of queries rejected because the
number of concurrent queries were at maximum.
.IP \(bu 4
\fB\fCcoredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode}\fR - histogram per upstream, RCODE
.IP \(bu 4
\fB\fCcoredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode}\fR- count of failed health checks per upstream.
.IP \(bu 4
\fB\fCcoredns_proxy_conn_cache_hits_total{proxy_name="forward", to, proto}\fR- count of connection cache hits per upstream and protocol.
.IP \(bu 4
\fB\fCcoredns_proxy_conn_cache_misses_total{proxy_name="forward", to, proto}\fR - count of connection cache misses per upstream and protocol.
.PP
Where \fB\fCto\fR is one of the upstream servers (\fBTO\fP from the config), \fB\fCrcode\fR is the returned RCODE
from the upstream, \fB\fCproto\fR is the transport protocol like \fB\fCudp\fR, \fB\fCtcp\fR, \fB\fCtcp-tls\fR.
.PP
The following metrics have recently been deprecated:
* \fB\fCcoredns_forward_healthcheck_failures_total{to, rcode}\fR
* Can be replaced with \fB\fCcoredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode}\fR
* \fB\fCcoredns_forward_requests_total{to}\fR
* Can be replaced with \fB\fCsum(coredns_proxy_request_duration_seconds_count{proxy_name="forward", to})\fR
* \fB\fCcoredns_forward_responses_total{to, rcode}\fR
* Can be replaced with \fB\fCcoredns_proxy_request_duration_seconds_count{proxy_name="forward", to, rcode}\fR
* \fB\fCcoredns_forward_request_duration_seconds{to, rcode}\fR
* Can be replaced with \fB\fCcoredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode}\fR
.SH "EXAMPLES"
.PP
Proxy all requests within \fB\fCexample.org.\fR to a nameserver running on a different port:
.PP
.RS
.nf
example.org {
forward . 127.0.0.1:9005
}
.fi
.RE
.PP
Send all requests within \fB\fClab.example.local.\fR to \fB\fC10.20.0.1\fR, all requests within \fB\fCexample.local.\fR (and not in
\fB\fClab.example.local.\fR) to \fB\fC10.0.0.1\fR, all others requests to the servers defined in \fB\fC/etc/resolv.conf\fR, and
caches results. Note that a CoreDNS server configured with multiple \fIforward\fP plugins in a server block will evaluate those
forward plugins in the order they are listed when serving a request. Therefore, subdomains should be
placed before parent domains otherwise subdomain requests will be forwarded to the parent domain's upstream.
Accordingly, in this example \fB\fClab.example.local\fR is before \fB\fCexample.local\fR, and \fB\fCexample.local\fR is before \fB\fC.\fR.
.PP
.RS
.nf
\&. {
cache
forward lab.example.local 10.20.0.1
forward example.local 10.0.0.1
forward . /etc/resolv.conf
}
.fi
.RE
.PP
The example above is almost equivalent to the following example, except that example below defines three separate plugin
chains (and thus 3 separate instances of \fIcache\fP).
.PP
.RS
.nf
lab.example.local {
cache
forward . 10.20.0.1
}
example.local {
cache
forward . 10.0.0.1
}
\&. {
cache
forward . /etc/resolv.conf
}
.fi
.RE
.PP
Load balance all requests between three resolvers, one of which has a IPv6 address.
.PP
.RS
.nf
\&. {
forward . 10.0.0.10:53 10.0.0.11:1053 [2003::1]:53
}
.fi
.RE
.PP
Forward everything except requests to \fB\fCexample.org\fR
.PP
.RS
.nf
\&. {
forward . 10.0.0.10:1234 {
except example.org
}
}
.fi
.RE
.PP
Proxy everything except \fB\fCexample.org\fR using the host's \fB\fCresolv.conf\fR's nameservers:
.PP
.RS
.nf
\&. {
forward . /etc/resolv.conf {
except example.org
}
}
.fi
.RE
.PP
Proxy all requests to 9.9.9.9 using the DNS-over-TLS (DoT) protocol, and cache every answer for up to 30
seconds. Note the \fB\fCtls_servername\fR is mandatory if you want a working setup, as 9.9.9.9 can't be
used in the TLS negotiation. Also set the health check duration to 5s to not completely swamp the
service with health checks.
.PP
.RS
.nf
\&. {
forward . tls://9.9.9.9 {
tls\_servername dns.quad9.net
health\_check 5s
}
cache 30
}
.fi
.RE
.PP
Or configure other domain name for health check requests
.PP
.RS
.nf
\&. {
forward . tls://9.9.9.9 {
tls\_servername dns.quad9.net
health\_check 5s domain example.org
}
cache 30
}
.fi
.RE
.PP
Or with multiple upstreams from the same provider
.PP
.RS
.nf
\&. {
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls\_servername cloudflare\-dns.com
health\_check 5s
}
cache 30
}
.fi
.RE
.PP
Or when you have multiple DoT upstreams with different \fB\fCtls_servername\fRs, you can do the following:
.PP
.RS
.nf
\&. {
forward . 127.0.0.1:5301 127.0.0.1:5302
}
\&.:5301 {
forward . tls://8.8.8.8 tls://8.8.4.4 {
tls\_servername dns.google
}
}
\&.:5302 {
forward . tls://1.1.1.1 tls://1.0.0.1 {
tls\_servername cloudflare\-dns.com
}
}
.fi
.RE
.PP
The following would try 1.2.3.4 first. If the response is \fB\fCNXDOMAIN\fR, try 5.6.7.8. If the response from 5.6.7.8 is \fB\fCNXDOMAIN\fR, try 9.0.1.2.
.PP
.RS
.nf
\&. {
forward . 1.2.3.4 {
next NXDOMAIN
}
forward . 5.6.7.8 {
next NXDOMAIN
}
forward . 9.0.1.2 {
}
}
.fi
.RE
.PP
In the following example, if the response from \fB\fC1.2.3.4\fR is \fB\fCSERVFAIL\fR or \fB\fCREFUSED\fR, it will try \fB\fC5.6.7.8\fR. If the response from \fB\fC5.6.7.8\fR is \fB\fCSERVFAIL\fR or \fB\fCREFUSED\fR, it will try \fB\fC9.0.1.2\fR.
.PP
.RS
.nf
\&. {
forward . 1.2.3.4 5.6.7.8 9.0.1.2 {
policy sequential
failover SERVFAIL REFUSED
}
}
.fi
.RE
.SH "SEE ALSO"
.PP
RFC 7858
\[la]https://tools.ietf.org/html/rfc7858\[ra] for DNS over TLS.