Add blocking: blocklists and block/allow rules with BIND response policy zones

jarld downloads blocklists (Adblock, hosts or plain domains), checks them
daily and reloads named only when a list changed; your own block and
allow rules take precedence, and the most specific rule wins. Lists and
rules apply per view (default: every view that offers recursion). Web UI
Blocking page with name checks, jarl blocklist and jarl block, the
/blocking API, blocked counts in the statistics. Database schema 6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-10 09:24:19 +00:00
1 parent 436cd79ec9
commit 9fc23310bd
54 files changed
+4269 -85

No files matched your search

+17 -10
View File
@@ -69,8 +69,9 @@ func (h *StatsHooks) statsStatement(user *model.Option) string {
}
// loggingStatement returns the logging statement with Jarl's channel and
// the responses category, merged into the user's own if there is one.
func (h *StatsHooks) loggingStatement(user *model.Option) string {
// the responses category (and rpz, for blocking's rewrites), merged into
// the user's own if there is one.
func (h *StatsHooks) loggingStatement(user *model.Option, rpz bool) string {
var st *namedconf.Stmt
if user != nil {
var err error
@@ -84,15 +85,21 @@ func (h *StatsHooks) loggingStatement(user *model.Option) string {
b := st.FirstBlock()
// Channels must be defined before the categories that use them.
b.Stmts = append([]*namedconf.Stmt{h.logChannel()}, b.Stmts...)
merged := false
for _, s := range b.Stmts {
if s.Keyword() == "category" && strings.EqualFold(s.Arg(0), "responses") && s.FirstBlock() != nil {
s.FirstBlock().Stmts = append(s.FirstBlock().Stmts, namedconf.NewStmt(StatsChannelName))
merged = true
}
categories := []string{"responses"}
if rpz {
categories = append(categories, "rpz")
}
if !merged {
b.Stmts = append(b.Stmts, namedconf.NewStmt("category", "responses", namedconf.NewBlock(namedconf.NewStmt(StatsChannelName))))
for _, cat := range categories {
merged := false
for _, s := range b.Stmts {
if s.Keyword() == "category" && strings.EqualFold(s.Arg(0), cat) && s.FirstBlock() != nil {
s.FirstBlock().Stmts = append(s.FirstBlock().Stmts, namedconf.NewStmt(StatsChannelName))
merged = true
}
}
if !merged {
b.Stmts = append(b.Stmts, namedconf.NewStmt("category", cat, namedconf.NewBlock(namedconf.NewStmt(StatsChannelName))))
}
}
prefix := ""
if user != nil {