Internet exposure checks and response rate limiting
Jarl works out which views are reachable from the internet (match-clients
ending in a catch-all, not private-looking addresses: an internal view of a
global IPv6 prefix is still yours; a server without views: open allow-query
and a non-private listen address), with a per-view override (schema 9), and
checks public ones: rate limiting, open resolver, minimal-any, cache
snooping, open NOTIFY and transfers, version and host name, management
interfaces. Fixes are staged like any change, including rate limiting from
ISC's example in log-only mode with the secondaries exempt, then enforcing.
named logs what rate limiting limits (or would, in log-only mode, where its
counters don't move) as query-errors; Jarl routes those lines to its log
and counts them (rrl breakdown, ratelimited top lists, Prometheus
jarl_ratelimit_logged_total), shown on the new Exposure page.
A change that newly opens a public view up must be confirmed (accept_risk,
--accept-risk, a checkbox on the Changes page; 409 confirm_risk
otherwise). Findings can be acknowledged with a reason and stay visible as
info. GET /exposure, POST /exposure/fix|ack|unack, jarl exposure,
docs/exposure.md.
Also fixes query statistics skipping TSIG-signed queries ("IP#port/key
NAME" in named's log).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cf550bd512
commit
bdd7acfd3b
50 files changed
+2019
-52
No files matched your search
@@ -11,6 +11,7 @@ package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -37,6 +38,9 @@ type Problem struct {
|
||||
Zone string `json:"zone,omitempty"`
|
||||
View string `json:"view,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
// Acknowledged is set when an exposure finding was accepted on
|
||||
// purpose (it is then info, not a warning).
|
||||
Acknowledged *model.Acknowledgement `json:"acknowledged,omitempty"`
|
||||
}
|
||||
|
||||
// Key identifies a problem independently of object IDs, so problems can be
|
||||
@@ -67,6 +71,10 @@ type Options struct {
|
||||
// ExternalKeysUnknown is set when an included file could not be read,
|
||||
// so references to unknown keys are not reported.
|
||||
ExternalKeysUnknown bool
|
||||
// LocalAddrs are this host's addresses: a server without views is
|
||||
// public when named listens on one that isn't private
|
||||
// (docs/exposure.md).
|
||||
LocalAddrs []netip.Addr
|
||||
}
|
||||
|
||||
// Result holds the problems found.
|
||||
@@ -140,8 +148,10 @@ func State(s *model.State, opts Options) []Problem {
|
||||
c.checkZones()
|
||||
c.checkOptions()
|
||||
c.checkSecurity()
|
||||
c.checkExposure()
|
||||
c.checkDNSSEC()
|
||||
c.checkBlocking()
|
||||
c.applyAcks()
|
||||
sortProblems(c.problems)
|
||||
return c.problems
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user