Documentation
¶
Index ¶
- Constants
- type Config
- func (c *Config) ForwardZoneFor(qname string) *ForwardZoneConfig
- func (c *Config) QnameMinimizeParams() (maxCount, oneLabel int)
- func (c *Config) RFC8198Enabled() bool
- func (c *Config) RFC9520Enabled() bool
- func (c *Config) ServerVersion() string
- func (c *Config) UndecodedKeys() []string
- func (c *Config) Validate() error
- type DNS64Config
- type Duration
- type ECSConfig
- type ForwardZoneConfig
- type KubernetesConfig
- type KubernetesTTLConfig
- type Plugin
- type RPZ
- type RPZZone
- type RecursionFirewallConfig
- type RecursionFirewallMode
- type ViewConfig
Constants ¶
const ( RecursionFirewallModeOff RecursionFirewallMode = "off" RecursionFirewallModeShadow RecursionFirewallMode = "shadow" RecursionFirewallModeEnforce RecursionFirewallMode = "enforce" DefaultRecursionFirewallMaxOutboundQueries uint32 = 128 DefaultRecursionFirewallMaxInternalQueries uint32 = 32 DefaultRecursionFirewallMaxDNSKEYCandidates uint32 = 4 DefaultRecursionFirewallMaxRRsetSignatureChecks uint32 = 8 DefaultRecursionFirewallMaxSignatureChecks uint32 = 32 DefaultRecursionFirewallMaxDSDigests uint32 = 32 DefaultRecursionFirewallMaxNSEC3Hashes uint32 = 32 DefaultRecursionFirewallMaxConcurrentCrypto uint32 = 32 DefaultRecursionFirewallFailureCacheSize int = 4096 DefaultRecursionFirewallFailureCacheMinTTL = 5 * time.Second DefaultRecursionFirewallFailureCacheMaxTTL = 5 * time.Minute )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
Version string
Directory string
BlockLists []string
BlockListDir string
RootServers []string
Root6Servers []string
DNSSEC string
RFC8198 *bool `toml:"rfc8198"` // nil is default-on for backward compatibility
RFC9520 *bool `toml:"rfc9520"` // nil is default-on; false is an emergency kill switch
ServeStale bool `toml:"serve_stale"`
// ServeStaleMaxTTL caps how long a positive answer may be reused after
// its admitted TTL expires. Omission defaults to 24 hours. An explicit
// zero leaves the delegation lease as the only bound; in forwarder mode,
// where no delegation cut is learned, that means retention until eviction.
// Serve-stale itself remains opt-in through ServeStale.
ServeStaleMaxTTL Duration `toml:"serve_stale_max_ttl"`
RootKeys []string
FallbackServers []string
ForwarderServers []string
// ForwardZones route individual zones to their own upstreams. They are
// consulted before ForwarderServers, which remains the whole-server
// setting: a query matching no zone resolves normally.
ForwardZones []ForwardZoneConfig `toml:"forward_zone"`
AccessList []string
LogLevel string
AccessLog string
Bind string
BindTLS string
BindDOH string
BindDOQ string
TLSCertificate string
TLSPrivateKey string
API string
BearerToken string //nolint:gosec // G117 - not a hardcoded credential, loaded from config file
Nullroute string
Nullroutev6 string
HostsFile string
OutboundIPs []string
OutboundIP6s []string
Timeout Duration
QueryTimeout Duration
Expire uint32
CacheSize int
Prefetch uint32
Maxdepth int
RateLimit int
ClientRateLimit int
NSID string
Blocklist []string
Whitelist []string
Chaos bool
// QnameMinLevel is deprecated and retained so older configs keep
// parsing. It capped minimization by delegation depth rather than by
// the queries a lookup spends, which is what RFC 9156 section 2.3
// bounds. A non-zero value here is folded onto QnameMaxMinimizeCount
// when that is unset. Remove it from new configs.
QnameMinLevel int `toml:"qname_min_level"`
// QnameMaxMinimizeCount is RFC 9156's MAX_MINIMISE_COUNT: the total
// minimized queries one lookup may spend before the full name goes
// out. 0 disables minimization entirely. A pointer because an explicit
// zero and an absent key mean different things: written zero is the
// operator switching minimization off, and it must win even when the
// deprecated qname_min_level is still in the file; only an absent key
// falls back to it.
QnameMaxMinimizeCount *int `toml:"qname_max_minimize_count"`
// QnameMinimizeOneLabel is RFC 9156's MINIMISE_ONE_LAB: how many of
// those queries add a single label before the remaining labels are
// grouped over the queries left. 0 selects the RFC's suggested 4;
// grouping from the first query would expose a deep name almost at
// once, so it is not an available setting.
QnameMinimizeOneLabel int `toml:"qname_minimize_one_label"`
// HyperlocalRoot serves the root zone from a local copy (RFC 8806):
// transferred over AXFR from the root servers that publish it,
// verified against the ZONEMD digest (RFC 8976) chained to the root
// trust anchors, refreshed on the zone's own SOA schedule, and
// withdrawn past its SOA expire — the resolver then walks to the real
// root servers as if the copy never existed.
HyperlocalRoot bool `toml:"hyperlocal_root"`
// HyperlocalRootSources overrides the built-in transfer sources
// (host:port). Empty selects the RFC 8806 appendix set.
HyperlocalRootSources []string `toml:"hyperlocal_root_sources"`
EmptyZones []string
// RPZ subscribes the resolver to Response Policy Zones — operator- or
// vendor-fed zones that rewrite, deny, or drop answers for the names
// they list, in the standard RPZ encoding so existing feeds work
// unmodified. Off by default; semantics in the README's Response
// Policy Zones section.
RPZ RPZ `toml:"rpz"`
// Views are per-client static answers, evaluated in order. A
// query whose source IP falls in a view's Sources gets that
// view's Records as the response; non-matching queries fall
// through to the rest of the middleware chain (blocklist,
// resolver, etc.).
Views []ViewConfig
// Dnstap configuration
DnstapSocket string
DnstapIdentity string
DnstapVersion string
DnstapLogQueries bool
DnstapLogResponses bool
DnstapFlushInterval int
// Domain metrics configuration
DomainMetrics bool
DomainMetricsLimit int
// Kubernetes middleware configuration as a section
Kubernetes KubernetesConfig `toml:"kubernetes"`
// DNS64 middleware configuration (RFC 6147). Translates A
// records into AAAA records embedded in a configured IPv6
// prefix, so an IPv6-only client can reach IPv4-only services.
DNS64 DNS64Config `toml:"dns64"`
// ECS (EDNS Client Subnet, RFC 7871) policy. Default-disabled
// per §11 privacy guidance: the resolver strips client ECS on
// the way out unless the operator opts in via [ecs].enabled.
// Stage 1 of the feature uses Enabled / ForwardV4Max /
// ForwardV6Max / ClientNetworks for upstream forwarding; the
// remaining fields ride along for the Stage 2 cache changes
// so the on-disk schema only bumps once.
ECS ECSConfig `toml:"ecs"`
// RecursionFirewall bounds aggregate work across one recursive
// request tree. Shadow mode records limit crossings without
// changing responses; enforce mode terminates over-budget work.
RecursionFirewall RecursionFirewallConfig `toml:"recursion_firewall"`
Plugins map[string]Plugin
CookieSecret string
IPv6Access bool `toml:"ipv6access"`
// TCP connection pooling configuration
TCPKeepalive bool
RootTCPTimeout Duration // Timeout for root server TCP connections
TLDTCPTimeout Duration // Timeout for TLD server TCP connections
TCPMaxConnections int // Maximum number of TCP connections to pool
// Resolver concurrency limits
MaxConcurrentQueries int // Maximum concurrent DNS queries (default 10000)
// Server ingress bounds. These are deliberately separate from
// MaxConcurrentQueries, which is the resolver's upstream fan-out
// semaphore. Left at zero, each derives from the machine's resource
// plan (memory, CPUs, descriptor limit); nothing is preallocated —
// admission is capped, slabs are created on demand and parked in an
// idle cache between requests.
IngressWorkers int // Fixed handler workers per listener (default: derived from CPUs and memory)
IngressQueue int // Ready-queue depth before a job is served on its own goroutine (default 64)
IngressTCPConns int // Concurrent inbound TCP/DoT connection cap (default: derived from available memory)
// MemoryTrim returns a burst's slab memory to the operating system
// after a long idle. Off by default: the trim is one synchronous GC
// over the whole process, which a busy or big-memory server never
// needs and a single small core feels. Meant for memory-constrained
// devices (containers on routers, small VPSes) where resident memory
// after a traffic burst matters more than an idle-time pause.
MemoryTrim bool
// Reflex: DNS amplification/reflection attack detection
ReflexEnabled bool // Enable amplification attack detection
ReflexBlockMode bool // If false, only log but don't block
ReflexLearningMode bool // If true, log detections but don't block
ReflexThreshold float64 // Suspicion threshold (0.0-1.0, default: 0.7)
// contains filtered or unexported fields
}
Config type.
func (*Config) ForwardZoneFor ¶ added in v1.8.2
func (c *Config) ForwardZoneFor(qname string) *ForwardZoneConfig
ForwardZoneFor returns the most specific configured forward zone covering qname, or nil when the query resolves normally. Most specific wins so a narrower zone can be pointed somewhere else than the one containing it.
A zone carrying no servers at all is skipped, but only as a guard for a Config built in code: validateForwardZones refuses one at startup, because letting its subtree resolve publicly is the leak configuring the zone was meant to prevent. A zone whose servers are configured but turn out unusable still matches here, and the forwarder fails those queries rather than sending them to the public upstreams.
The scan is linear because a forward-zone list is a handful of entries an operator wrote by hand; an index would cost more to keep honest than it saves.
func (*Config) QnameMinimizeParams ¶ added in v1.8.1
QnameMinimizeParams resolves the RFC 9156 minimization parameters: the deprecated qname_min_level is folded in when the current key is unset, and the pair is clamped into a shape the resolver can use. It is pure and idempotent, so a Config built in code — tests, embedders — reaches the same values Load produces.
func (*Config) RFC8198Enabled ¶ added in v1.7.4
RFC8198Enabled reports whether aggressive NSEC/NSEC3 denial synthesis is enabled. Omission is default-on; an explicit false is the operational kill switch. RFC 8020 NXDOMAIN subtree cuts are controlled independently.
func (*Config) RFC9520Enabled ¶ added in v1.7.4
RFC9520Enabled reports whether shared resolution-failure caching is enabled. Omission is default-on because RFC 9520 requires resolvers to cache failures; explicit false exists as an operational rollback switch for the shared question and authority-zone state.
func (*Config) ServerVersion ¶ added in v1.0.0
(*Config).ServerVersion serverVersion return current server version.
func (*Config) UndecodedKeys ¶ added in v1.8.2
UndecodedKeys returns the config keys that were present in the file and matched no setting — typos, or settings a previous version understood. They have no effect on this server.
func (*Config) Validate ¶ added in v1.8.2
Validate reports what is wrong with a loaded configuration.
Every problem is collected and reported together. An operator fixing a config file wants the whole list, not one error per run — and a DNS server that refuses to start is a visible failure, where one that starts with a setting it silently ignored is not.
The rules only reject what cannot be right: an address that does not parse, a value outside an enumerated set, a file that is not there. Anything this package cannot judge — whether an upstream answers, whether a certificate matches its key — belongs to the component that uses it.
type DNS64Config ¶ added in v1.6.7
type DNS64Config struct {
Enabled bool `toml:"enabled"`
Prefixes []string `toml:"prefixes"`
ClientNetworks []string `toml:"client_networks"`
ExcludeZones []string `toml:"exclude_zones"`
ExcludeANetworks []string `toml:"exclude_a_networks"`
ExcludeAAAANetworks []string `toml:"exclude_aaaa_networks"`
}
DNS64Config holds DNS64 middleware configuration (RFC 6147).
Prefixes lists Pref64::/n IPv6 prefixes used to embed IPv4 addresses in synthesised AAAA records. Each prefix length must be one of /32, /40, /48, /56, /64, /96 per RFC 6052 §2.2. Per RFC 6147 §5.2 every configured prefix synthesises in parallel: each upstream A record produces one AAAA per prefix, so a client receives every reachable Pref64 path in a single reply. When DNS64 is enabled but no usable prefix is configured the well-known 64:ff9b::/96 is the runtime default.
ClientNetworks restricts synthesis to clients whose source IP falls in one of the listed CIDRs. An empty list synthesises for every client; "::/0" plus "0.0.0.0/0" achieves the same and is the recommended explicit form.
ExcludeZones is a list of fully-qualified domain names whose AAAA responses are never synthesised (their original NODATA / NXDOMAIN flows through unchanged). Useful for opting out specific zones when some other middleware is expected to handle IPv6.
ExcludeANetworks is the RFC 6147 §5.1.4 / RFC 6052 §3.1 "do not translate" set. IPv4 addresses inside any listed CIDR are dropped from synthesis when the well-known prefix 64:ff9b::/96 is in use. Operator-chosen network-specific prefixes ignore this list — they picked the prefix knowing the network's reachability. When the field is omitted entirely (nil) and the well-known prefix is active, a runtime default list mirroring the IANA Special-Purpose Address Registry is applied; declaring an explicit empty list opts out.
ExcludeAAAANetworks lists IPv6 prefixes whose AAAA records in the upstream response must be filtered before deciding pass-through vs synthesis (RFC 6147 §5.1.4). The default ::ffff:0:0/96 (IPv4- mapped IPv6) keeps misconfigured upstreams from leaking non-routable addresses into the client. When every AAAA in the upstream answer is excluded, the response is treated as if no AAAA records were returned and synthesis proceeds. Declaring an explicit empty list opts out of filtering.
type Duration ¶ added in v0.3.0
Duration type.
func (*Duration) UnmarshalText ¶ added in v0.3.0
(*Duration).UnmarshalText unmarshalText for duration type.
type ECSConfig ¶ added in v1.7.0
type ECSConfig struct {
Enabled bool `toml:"enabled"`
ForwardV4Max uint8 `toml:"forward_v4"`
ForwardV6Max uint8 `toml:"forward_v6"`
ClientNetworks []string `toml:"client_networks"`
CacheLimitTTL Duration `toml:"cache_limit_ttl"`
MinScopeV4 uint8 `toml:"min_scope_v4"`
MinScopeV6 uint8 `toml:"min_scope_v6"`
}
ECSConfig holds the EDNS Client Subnet middleware configuration (RFC 7871). Strictly opt-in: when Enabled is false, the resolver strips every client-supplied ECS option before forwarding upstream, matching the §11 privacy stance and SDNS's historical behaviour.
When Enabled is true, ForwardV4Max and ForwardV6Max cap the source-prefix length we'll forward — narrower (more specific) client prefixes get clamped down. Defaults are /24 and /56, matching common operator practice.
ClientNetworks restricts forwarding to known clients (corporate networks, internal load balancers, CDN edges); empty means every eligible client.
CacheLimitTTL, MinScopeV4, and MinScopeV6 control how scoped answers are stored (Stage 2). They live here so the on-disk schema only bumps once across the rollout, even though Stage 1 doesn't consume them yet.
type ForwardZoneConfig ¶ added in v1.8.2
type ForwardZoneConfig struct {
// Name is the zone apex. Queries at or below it are forwarded.
Name string `toml:"name"`
// Servers are the upstreams, in the same forms as forwarderservers:
// "ip:port", "tls://ip:port", or an https:// URL.
Servers []string `toml:"servers"`
}
ForwardZoneConfig sends one zone's queries to named recursive upstreams instead of resolving them from the root.
This is forwarding in the RFC 8499 §6 sense — the query goes out with RD=1 to a server that resolves on our behalf — not a stub zone, which points at a zone's own authoritative servers with RD=0.
A forwarded zone is not validated here. Answers carry whatever the upstream asserted, exactly as in whole-server forwarder mode, so pointing a signed public zone at an upstream silently gives up local DNSSEC validation for it. The intended use is the opposite case: an internal zone the public namespace cannot resolve at all.
type KubernetesConfig ¶ added in v1.6.0
type KubernetesConfig struct {
Enabled bool `toml:"enabled"`
ClusterDomain string `toml:"cluster_domain"`
// KillerMode is deprecated and ignored. The kubernetes middleware
// always uses the sharded registry; the field is retained so
// older configs parse without error. Remove it from new configs.
KillerMode bool `toml:"killer_mode"`
Kubeconfig string `toml:"kubeconfig"`
// Demo populates the registry with synthetic services so the
// middleware can be exercised without a real cluster
// (development / tests). It is NEVER safe to enable in
// production: the middleware will answer synthesised names
// that look real. Independent from Enabled.
Demo bool `toml:"demo"`
TTL KubernetesTTLConfig `toml:"ttl"`
}
KubernetesConfig holds Kubernetes middleware configuration
type KubernetesTTLConfig ¶ added in v1.6.0
type KubernetesTTLConfig struct {
Service uint32 `toml:"service"`
Pod uint32 `toml:"pod"`
SRV uint32 `toml:"srv"`
PTR uint32 `toml:"ptr"`
}
KubernetesTTLConfig holds TTL settings for different record types
type RPZ ¶ added in v1.8.2
type RPZ struct {
Enabled bool `toml:"enabled"`
// Mode is "shadow" (the default: every match is counted and logged,
// nothing is rewritten) or "enforce". An operator turns a new feed on
// in shadow, watches the counters, then flips.
Mode string `toml:"mode"`
Zones []RPZZone `toml:"zone"`
}
RPZ is the rpz block: the global switch and mode, and the ordered policy zone list. Order is evaluation order — the first zone with a match wins, which is the draft's precedence rule 1.
type RPZZone ¶ added in v1.8.2
type RPZZone struct {
// Name labels the zone in metrics, logs, and the EDE text.
Name string `toml:"name"`
// File is the policy zone in standard zone-file format.
File string `toml:"file"`
// Source is the AXFR primary (host:port). The zone then follows its
// own SOA schedule — probe on refresh, transfer on serial change,
// withdraw past expire — and File must be empty.
Source string `toml:"source"`
// Origin is the policy zone's apex, the name the AXFR asks for.
// Required with Source.
Origin string `toml:"origin"`
// TsigKey authenticates the transfer when the provider requires it:
// "name:algorithm:base64-secret", e.g.
// "feedkey.:hmac-sha256.:c2VjcmV0". Empty for an unsigned transfer.
TsigKey string `toml:"tsig_key"`
// Policy overrides every action the zone's rules carry:
// given|passthru|nxdomain|nodata|drop|tcp-only|cname|disabled.
// "given" (or empty) uses what each rule says; "disabled" logs what
// would have happened and lets a later zone act.
Policy string `toml:"policy"`
// Cname is the rewrite target when Policy is "cname", the draft's
// walled-garden override. Required then, forbidden otherwise.
Cname string `toml:"cname"`
}
RPZZone is one [[rpz.zone]] entry. A zone is fed exactly one way: File for a local file, or Source+Origin for an AXFR secondary.
type RecursionFirewallConfig ¶ added in v1.7.4
type RecursionFirewallConfig struct {
Mode RecursionFirewallMode `toml:"mode"`
MaxOutboundQueries uint32 `toml:"max_outbound_queries"`
MaxInternalQueries uint32 `toml:"max_internal_queries"`
MaxDNSKEYCandidates uint32 `toml:"max_dnskey_candidates"`
MaxRRsetSignatureChecks uint32 `toml:"max_rrset_signature_checks"`
MaxSignatureChecks uint32 `toml:"max_signature_checks"`
MaxDSDigests uint32 `toml:"max_ds_digests"`
MaxNSEC3Hashes uint32 `toml:"max_nsec3_hashes"`
MaxConcurrentCrypto uint32 `toml:"max_concurrent_crypto"`
FailureCacheSize int `toml:"failure_cache_size"`
FailureCacheMinTTL Duration `toml:"failure_cache_min_ttl"`
FailureCacheMaxTTL Duration `toml:"failure_cache_max_ttl"`
}
RecursionFirewallConfig controls aggregate and local recursive work limits.
A zero limit means "use the default", not unlimited. Operators that need to disable accounting use Mode=off explicitly.
func (*RecursionFirewallConfig) Normalize ¶ added in v1.7.4
func (c *RecursionFirewallConfig) Normalize()
Normalize applies omission-safe defaults. It deliberately does not silently repair an unknown mode; Validate reports that typo to the operator instead of selecting a security policy by accident.
func (RecursionFirewallConfig) Validate ¶ added in v1.7.4
func (c RecursionFirewallConfig) Validate() error
Validate verifies the normalized recursion-firewall policy.
type RecursionFirewallMode ¶ added in v1.7.4
type RecursionFirewallMode string
RecursionFirewallMode controls whether request-tree work limits are disabled, observed, or enforced.
type ViewConfig ¶ added in v1.6.6
ViewConfig describes a single per-client static-answer view. Zone is a free-form label that names the view in logs and errors. Networks are CIDR strings; a query is dispatched to this view if its source IP is contained in any of them. Answers are DNS resource records in standard zone-file format; wildcard owners (e.g. "*.example.lan.") match any name strictly more specific than the suffix per RFC 4592.