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:
1 parent
436cd79ec9
commit
9fc23310bd
54 files changed
+4269
-85
No files matched your search
+57
-2
@@ -13,7 +13,7 @@ set -u
|
||||
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
||||
WORK=${WORK:-$(mktemp -d /tmp/jarl-e2e.XXXXXX)}
|
||||
E=$WORK
|
||||
DNS=${DNS_PORT:-25353}; CTL=${CTL_PORT:-25953}; HTTP=${HTTP_PORT:-28053}
|
||||
DNS=${DNS_PORT:-25353}; CTL=${CTL_PORT:-25953}; HTTP=${HTTP_PORT:-28053}; LISTS=${LISTS_PORT:-28054}
|
||||
if [ -n "${JARL_BIND_ROOT:-}" ]; then
|
||||
B=$JARL_BIND_ROOT
|
||||
export LD_LIBRARY_PATH=$(echo $B/usr/lib/*-linux-gnu | cut -d' ' -f1)
|
||||
@@ -30,8 +30,9 @@ done
|
||||
mkdir -p $E/legacy $E/cache $E/data
|
||||
JARLD=$E/jarld J=$E/jarl
|
||||
(cd "$ROOT" && go build -o $JARLD ./cmd/jarld && go build -o $J ./cmd/jarl) || exit 1
|
||||
NAMED_PID= JARLD_PID=
|
||||
NAMED_PID= JARLD_PID= LISTS_PID=
|
||||
cleanup() {
|
||||
[ -n "$LISTS_PID" ] && kill $LISTS_PID 2>/dev/null
|
||||
if [ "${KEEP:-}" = 1 ]; then echo "left running in $WORK (named $NAMED_PID, jarld $JARLD_PID)"; return; fi
|
||||
[ -n "$JARLD_PID" ] && kill $JARLD_PID 2>/dev/null
|
||||
[ -n "$NAMED_PID" ] && kill $NAMED_PID 2>/dev/null
|
||||
@@ -409,6 +410,60 @@ run "wipe the child" 0 $J zone dnssec wipe sub.adbraun.test --view external --ye
|
||||
run "delete the child" 0 $J zone delete sub.adbraun.test --view external --yes
|
||||
run "remove the delegation" 0 $J record delete adbraun.test sub NS --view external --yes
|
||||
|
||||
# Blocking (docs/blocking.md). It only changes answers to recursive
|
||||
# queries, so these ask with recursion and look at which policy zone (if
|
||||
# any) the answer came from.
|
||||
rpz() {
|
||||
$DIG +tries=1 +time=3 -p $DNS @127.0.0.1 "$1" A | awk '$4 == "SOA" && $1 ~ /jarl\.invalid\.$/ {print $1; f = 1} END {if (!f) print "none"}'
|
||||
}
|
||||
expect_rpz() { # DESC NAME WANT: named reloads in the background, so wait a little
|
||||
local got
|
||||
for i in $(seq 30); do got=$(rpz "$2"); [ "$got" = "$3" ] && break; sleep 0.2; done
|
||||
if [ "$got" = "$3" ]; then ok "$1: $2 -> $3"; else bad "$1: $2 -> $got, want $3"; fi
|
||||
}
|
||||
mkdir -p $E/lists
|
||||
printf '# test list\n||tracker.adbraun.test^\n0.0.0.0 ads.adbraun.test\nnot a domain\n' > $E/lists/list.txt
|
||||
(cd $E/lists && exec python3 -m http.server --bind 127.0.0.1 $LISTS) > /dev/null 2>&1 &
|
||||
LISTS_PID=$!
|
||||
run "block add" 0 $J block add blocked.adbraun.test
|
||||
expect_rpz "a rule blocks the name" blocked.adbraun.test rules.jarl.invalid.
|
||||
expect_rpz "and the names below it" a.blocked.adbraun.test rules.jarl.invalid.
|
||||
expect_rpz "other names are answered" www.adbraun.test none
|
||||
run "named.conf has the policy" 0 grep -q 'response-policy' $E/etc-jarl/named.conf
|
||||
for i in $(seq 25); do curl -s -o /dev/null http://127.0.0.1:$LISTS/list.txt && break; sleep 0.2; done
|
||||
run "blocklist add" 0 $J blocklist add test http://127.0.0.1:$LISTS/list.txt
|
||||
run "blocklist refresh" 0 $J blocklist refresh test
|
||||
contains "test: 2 domains (1 lines skipped)"
|
||||
expect_rpz "an Adblock entry blocks the names below it" x.tracker.adbraun.test test.blocklist.jarl.invalid.
|
||||
expect_rpz "a hosts entry blocks the name" ads.adbraun.test test.blocklist.jarl.invalid.
|
||||
expect_rpz "but not the names below it" sub.ads.adbraun.test none
|
||||
run "blocklist list" 0 $J blocklist list
|
||||
contains "^test *ok *2 "
|
||||
run "block allow" 0 $J block allow ok.tracker.adbraun.test
|
||||
expect_rpz "an allow rule beats the list" deep.ok.tracker.adbraun.test none
|
||||
expect_rpz "the rest of the list still blocks" x.tracker.adbraun.test test.blocklist.jarl.invalid.
|
||||
run "block check" 0 $J block check deep.ok.tracker.adbraun.test
|
||||
contains "allowed by your rule"
|
||||
# The test server dates the file to the second, and the download above
|
||||
# remembers that date: change it a second later, as a real list would.
|
||||
sleep 1.1
|
||||
printf '||new.adbraun.test^\n' > $E/lists/list.txt
|
||||
run "blocklist refresh after the list changed" 0 $J blocklist refresh test
|
||||
expect_rpz "the new version applies" x.new.adbraun.test test.blocklist.jarl.invalid.
|
||||
expect_rpz "and replaces the old one" x.tracker.adbraun.test none
|
||||
printf '<html>gone</html>\n' > $E/lists/list.txt
|
||||
run "a broken download fails (exit 2)" 2 $J blocklist refresh test --force
|
||||
contains "no domains found"
|
||||
expect_rpz "and the previous version stays" x.new.adbraun.test test.blocklist.jarl.invalid.
|
||||
run "blocklist disable" 0 $J blocklist disable test
|
||||
expect_rpz "a disabled list doesn't block" x.new.adbraun.test none
|
||||
run "blocklist delete" 0 $J blocklist delete test --yes
|
||||
run "block delete" 0 $J block delete blocked.adbraun.test
|
||||
expect_rpz "a deleted rule doesn't block" blocked.adbraun.test none
|
||||
run "block delete (allow rule)" 0 $J block delete ok.tracker.adbraun.test
|
||||
run "no blocking left in named.conf" 1 grep -q 'response-policy' $E/etc-jarl/named.conf
|
||||
kill $LISTS_PID 2>/dev/null; LISTS_PID=
|
||||
|
||||
run "status at the end" 0 $J status
|
||||
contains "Drift:.*none"
|
||||
|
||||
|
||||
Reference in new issue
Block a user