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:
adamandClaude Opus 5.5 committed 2026-10-12 10:38:56 +01:00
1 parent cf550bd512
commit bdd7acfd3b
50 files changed
+2019 -52

No files matched your search

+12
View File
@@ -489,3 +489,15 @@ details.view-picker summary { cursor: pointer; padding: 5px 8px; border: 1px sol
details.view-picker[open] .view-picker-list { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; min-width: 14em; max-height: 260px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; padding: 8px 10px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
ul.plain li { padding: 3px 0; }
.query-details { margin: 8px 0; }
/* Internet exposure findings */
.findings { display: flex; flex-direction: column; gap: 8px; }
.finding { display: flex; gap: 12px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--line); border-left-width: 3px; border-radius: 6px; }
.finding.warning { border-left-color: var(--warn); }
.finding.error { border-left-color: var(--err); }
.finding.acked, .finding.info { border-left-color: var(--line); color: var(--muted); }
.finding .actions { flex-shrink: 0; }
.risk-confirm { margin-top: 8px; }
a.card.link { color: inherit; text-decoration: none; }
a.card.link:hover { border-color: var(--accent, var(--link)); }