Added:
- Server statistics: named's memory and CPU (from /proc), cache size,
sockets and client counts against their limits (statistics channel,
rndc status), host memory and load, and free disk space. Memory and
CPU are kept over time as gauges (sum and sample count, averaged in
timelines). Statistics page Server section, jarl stats server,
GET /stats/server.
- jarl record add|set|delete|disable|enable --view a,b | all: the same
change in each view, applied as one changeset.
- Blocking can be paused until resumed (jarl block pause indefinitely,
"Until I resume", {"indefinitely": true}).
Changed:
- List options (allow-transfer, forwarders, ...) get their braces added
when given without them.
- The dashboard lists named-checkconf's warnings about the running
configuration; the CLI prints them after an apply.
- Stats page: tile and card rows fill their width, and the queries and
failed answers charts share margins so their time axes line up.
- Dashboard: options have their own tile.
- 24-hour times in the web UI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
268 lines
11 KiB
Markdown
268 lines
11 KiB
Markdown
# Blocking
|
|
|
|
Jarl can make named answer "this name doesn't exist" (NXDOMAIN) for ads,
|
|
trackers and malware, like Pi-hole does, for every device that uses your
|
|
server to resolve names. It has two parts:
|
|
|
|
- **Blocklists**: lists of domains published by others, which jarld
|
|
downloads and keeps up to date.
|
|
- **Your rules**: domains you block or allow yourself. They take precedence
|
|
over every list.
|
|
|
|
It uses BIND's own mechanism for this, response policy zones (RPZ), so named
|
|
does the blocking itself; jarld only prepares the lists.
|
|
|
|
- [Quick start](#quick-start)
|
|
- [Where blocking applies](#where-blocking-applies)
|
|
- [Your rules](#your-rules)
|
|
- [Blocklists](#blocklists)
|
|
- [Checking a name](#checking-a-name)
|
|
- [Pausing](#pausing)
|
|
- [Statistics](#statistics)
|
|
- [Memory and performance](#memory-and-performance)
|
|
- [How it works](#how-it-works)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
## Quick start
|
|
|
|
In the web UI, open **Blocking**, pick one of the well-known lists, and
|
|
click **Add list**. Or with the CLI:
|
|
|
|
```sh
|
|
jarl blocklist add hagezi-multi https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/multi.txt
|
|
jarl blocklist list # "ok" once downloaded, usually within seconds
|
|
jarl block check ads.doubleclick.net # blocked? by what?
|
|
jarl block allow cdn.example.com # something you need was blocked
|
|
```
|
|
|
|
Like every change in Jarl, adding a list or rule can be staged and reviewed
|
|
first (the web UI does this by default: apply it under **Changes**).
|
|
|
|
## Where blocking applies
|
|
|
|
Blocking changes the answers named gives when it resolves names for a
|
|
client (recursion). It doesn't change what the internet sees of your own
|
|
zones: other resolvers ask your server without recursion.
|
|
|
|
**Views.** A list or rule applies to the views you choose, or by default
|
|
to every view that offers recursion. With the usual split (an `internal`
|
|
view that resolves for your network, an `external` view that only answers
|
|
for your zones) that is just `internal`. A view that doesn't offer
|
|
recursion gets nothing, and naming one gives a warning. Without views,
|
|
blocking applies to the whole server.
|
|
|
|
**What it can't do:**
|
|
|
|
- Devices that don't use your server for DNS aren't affected. That includes
|
|
browsers using their own DNS over HTTPS, and devices with a hard-coded
|
|
resolver (8.8.8.8). A firewall rule that sends port 53 to your server, and
|
|
your network's DNS settings, are the usual answers.
|
|
- A device that validates DNSSEC itself sees a blocked name as a
|
|
validation failure rather than "doesn't exist". It's still blocked.
|
|
- A list can contain names in your own zones. They are blocked like any
|
|
other; allow them with a rule if that's not what you want.
|
|
|
|
## Your rules
|
|
|
|
A rule **blocks** or **allows** a domain and every name below it, or with
|
|
`--exact` (web UI: "only this exact name") just the domain itself.
|
|
|
|
```sh
|
|
jarl block add doubleclick.net # doubleclick.net and everything below it
|
|
jarl block add telemetry.example.com --exact # just that name
|
|
jarl block allow cdn.example.com --view internal # an exception, in one view
|
|
jarl block list
|
|
jarl block delete doubleclick.net # or: --id ID
|
|
```
|
|
|
|
**Precedence:** your rules come before every blocklist, and among your
|
|
rules the most specific one wins. With these rules:
|
|
|
|
| Rule | |
|
|
|------|-|
|
|
| block `example.com` | and below |
|
|
| allow `cdn.example.com` | exact |
|
|
|
|
`example.com` and `www.example.com` are blocked, `cdn.example.com` is
|
|
allowed, and `img.cdn.example.com` is blocked again (the allow rule was for
|
|
the exact name). An allow rule beats a blocklist entry whatever the lists
|
|
say.
|
|
|
|
There is one rule per domain and view; a second one is refused. A rule
|
|
takes effect as soon as the change is applied.
|
|
|
|
## Blocklists
|
|
|
|
**Formats.** Lists are read line by line; one list may mix formats:
|
|
|
|
| Line | Blocks |
|
|
|------|--------|
|
|
| `\|\|ads.example^` (Adblock) | the name and every name below it |
|
|
| `*.ads.example` | the name and every name below it |
|
|
| `0.0.0.0 ads.example` (hosts file, any address) | just the name |
|
|
| `ads.example` (plain domain) | just the name |
|
|
|
|
Comments (`#`, `!`), headers and blank lines are ignored. Lines that DNS
|
|
can't act on are skipped and counted: Adblock exceptions (`@@`), cosmetic
|
|
and URL rules, addresses, invalid names, and single labels (a broken list
|
|
can't block `com`). Prefer lists in Adblock format: they say which entries
|
|
cover the names below them.
|
|
|
|
**Well-known lists** (sizes in October 2026; they change):
|
|
|
|
| List | URL | Domains | Memory per view |
|
|
|------|-----|--------:|----------------:|
|
|
| Hagezi Light | `https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/light.txt` | 55,000 | ~65 MB |
|
|
| Hagezi Multi Normal | `https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/multi.txt` | 159,000 | ~190 MB |
|
|
| Hagezi Pro | `https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro.txt` | 195,000 | ~235 MB |
|
|
| OISD Small | `https://small.oisd.nl/` | 58,000 | ~70 MB |
|
|
| OISD Big | `https://big.oisd.nl/` | 241,000 | ~290 MB |
|
|
| StevenBlack hosts | `https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts` | 73,000 | ~45 MB |
|
|
|
|
One good list is usually enough; lists overlap a lot. Hagezi Multi Normal
|
|
is a balanced start; Light and OISD Small block less but almost never
|
|
something you need.
|
|
|
|
**Updates.** jarld checks each list every `blocking.refresh` (a day by
|
|
default) and downloads it only when the server says it changed. A new
|
|
version is checked with `named-checkzone` and replaces the old one only
|
|
when its content differs; named then reloads it. If a download or check
|
|
fails, named keeps using the previous version, jarld tries again within
|
|
the hour, and the dashboard shows the error. To update now:
|
|
|
|
```sh
|
|
jarl blocklist refresh # every list; or: refresh hagezi-multi [--force]
|
|
```
|
|
|
|
**Managing lists:**
|
|
|
|
```sh
|
|
jarl blocklist update hagezi-multi --view internal # --view auto: every view with recursion
|
|
jarl blocklist update hagezi-multi --url URL --name NEW-NAME
|
|
jarl blocklist disable hagezi-multi # stop using it, keep it (enable: back without a download)
|
|
jarl blocklist delete hagezi-multi
|
|
```
|
|
|
|
A list's state is **ok** (in use), **waiting** (not downloaded yet),
|
|
**error** (the last update failed; the previous version stays in use),
|
|
**disabled**, or **idle** (it applies to no view, so it does nothing).
|
|
|
|
## Checking a name
|
|
|
|
`jarl block check NAME`, or the box at the top of the Blocking page, says
|
|
for each view whether a name is blocked or allowed, and by which rule or
|
|
list entry:
|
|
|
|
```
|
|
$ jarl block check img.ads.example.com
|
|
view internal: blocked by blocklist hagezi-multi (entry *.ads.example.com)
|
|
view guest: allowed by your rule 12 (entry *.ads.example.com)
|
|
```
|
|
|
|
Views without blocking aren't listed.
|
|
|
|
In the web UI a blocked name gets an **Allow** button, and the statistics'
|
|
most blocked names link to this check.
|
|
|
|
## Pausing
|
|
|
|
To see whether blocking is what breaks a site, pause it: every name is
|
|
answered normally until the time is up (at most a day), then blocking
|
|
resumes by itself, also if jarld was restarted in between. A pause can
|
|
also last until someone resumes blocking (like Pi-hole's "indefinitely").
|
|
|
|
```sh
|
|
jarl block pause # 10 minutes; or: jarl block pause 1h
|
|
jarl block pause indefinitely
|
|
jarl block resume # end it now
|
|
```
|
|
|
|
In the web UI, **Pause blocking** is at the top of the Blocking page (with
|
|
**Until I resume** among the lengths), and the dashboard says while
|
|
blocking is paused. The lists stay loaded (the
|
|
rules zone just lets everything through), so pausing and resuming take
|
|
effect within a second. Pausing and resuming are recorded in the history
|
|
like other changes.
|
|
|
|
## Statistics
|
|
|
|
With [query statistics](stats.md) on (including `query_log`), Jarl counts
|
|
what blocking does: blocked queries over time (next to all queries) and
|
|
as a share of them, which rules and lists blocked them, the most blocked
|
|
names, and the clients with the most blocked queries (`jarl stats summary`,
|
|
`jarl stats top blocked`, `jarl stats top blocked-clients`, `jarl stats
|
|
breakdown blocklist`). Blocked answers are left out of the NXDOMAIN figures, which
|
|
are about names that really don't exist.
|
|
|
|
Without statistics named doesn't log what it blocks at all.
|
|
|
|
## Memory and performance
|
|
|
|
**Memory** is the cost to watch. named keeps each list in memory, once per
|
|
view it applies to: about 0.6 KB per policy record (an Adblock entry is
|
|
two records: the name, and the names below it). The Blocking page and
|
|
`jarl blocklist list` show the estimate per list. Hagezi Pro in one view
|
|
took named from 25 MB to 260 MB in a test with BIND 9.20; while a list
|
|
reloads, the old and new versions briefly coexist.
|
|
|
|
**Answers aren't slowed**: named looks blocked names up in memory, and
|
|
answers them without asking the internet.
|
|
|
|
**Updating a list** (Hagezi Pro: download, parse, check) takes jarld about
|
|
2 seconds. While named loads the new version, the queries that the loading
|
|
thread would have answered wait, up to half a second; this only happens
|
|
when the list changed, at most once per `blocking.refresh`.
|
|
|
|
**Other changes are unaffected**: the lists' contents never go through
|
|
Jarl's apply, so adding a record takes as long with a list as without.
|
|
|
|
Downloads are limited by `blocking.max_download_mb` and
|
|
`blocking.max_entries` ([configuration.md](configuration.md#blocking)).
|
|
|
|
## How it works
|
|
|
|
For each view (or the server, without views) Jarl writes a
|
|
`response-policy` statement and the policy zones it lists, in this order:
|
|
|
|
```
|
|
response-policy {
|
|
zone "rules.jarl.invalid" min-update-interval 0; # your rules
|
|
zone "hagezi-multi.blocklist.jarl.invalid" min-update-interval 0;
|
|
} qname-wait-recurse no break-dnssec yes;
|
|
```
|
|
|
|
- Policy zones are named under `.invalid`, so they can't clash with real
|
|
zones (zone names under `jarl.invalid` are refused). They allow no
|
|
queries or transfers.
|
|
- The rules zone of each view is a file next to your zone files
|
|
(`/var/lib/bind/jarl/VIEW/rules.jarl.invalid.rpz`) and shows up in the
|
|
changeset diff like any other.
|
|
- A list's file is `/var/cache/bind/jarl/blocklists/list-ID.rpz`, shared by
|
|
the views that use it. Until the first download it is an empty policy
|
|
zone, so named always starts. Files of deleted lists are removed.
|
|
- `qname-wait-recurse no` blocks without first resolving the real answer;
|
|
`break-dnssec yes` also blocks for clients that ask for DNSSEC data;
|
|
`min-update-interval 0` applies a new version at once.
|
|
- named looks names up in a policy zone like in any zone, so a wildcard
|
|
doesn't apply below a name the zone also contains. Jarl writes the zones
|
|
so that the most specific rule still wins.
|
|
- A `response-policy` option of your own can't be combined with Jarl's
|
|
blocking in the same view: Jarl refuses the change and says so.
|
|
- Rewrites are logged to Jarl's response log when statistics read it, and
|
|
not at all otherwise.
|
|
|
|
Lists and rules need the `blocking` permission ([permissions.md](permissions.md)).
|
|
|
|
## Troubleshooting
|
|
|
|
- **"no domains found in N lines"**: the URL didn't return a list (often an
|
|
HTML error page). Check it in a browser.
|
|
- **A list has no effect / is "idle"**: no view it applies to offers
|
|
recursion. Pick the view your devices use (`--view internal`).
|
|
- **Something is still answered**: `jarl block check NAME` shows whether
|
|
Jarl blocks it. If it does, the device probably doesn't use your server
|
|
(DNS over HTTPS, another resolver), or has the answer cached for a
|
|
while.
|
|
- **Something you need is blocked**: `jarl block check NAME` shows which
|
|
list; `jarl block allow NAME` overrides it.
|