The Protection settings page (Protection → Protection settings; up to 0.8.4 the page was called Protections, under the same menu) sets, for each profile (child, teenager, adult and devices given to nobody), what Warda does with each category:
| Category | Child | Teenager | Adult, nobody |
|---|---|---|---|
| Security threats (malware, phishing, scams) | block | block | block |
| VPN, proxies and encrypted DNS | block | block | allow |
| Adult content | block | block | allow |
| Violence and weapons | block | monitor | allow |
| Hate and terrorism (apology of terrorism, hate, discrimination) | block | block | allow |
| Drugs | block | monitor | allow |
| Gambling | block | block | allow |
| Piracy | monitor | allow | allow |
| Social networks | monitor | allow | allow |
| Videos and streaming | allow | allow | allow |
| Online games | allow | allow | allow |
| Job sites | allow | allow | allow |
| New domains (registered in the last 14 days) | allow | allow | allow |
These are the defaults. Monitoring lets the name through and records an alert (at most one per device and name per hour), shown on the dashboard and in the report of the person while they are a minor; it is offered for minors only, adults are never watched. Child sexual abuse material is always blocked, even over a personal allow rule; the other categories give way to the personal allow rules. A category is applied before the pauses of "something is broken", also to the names behind a CNAME, and its blocks cannot be unblocked in one click. A device that changes address is recognised again within seconds. When a minor becomes an adult or a person is removed, their alerts are deleted.
VPN, proxies and encrypted DNS (and iCloud Private Relay) have their list,
always loaded: for an adult's device
(allowed), Warda records a notice shown to that adult only, in My
account and on their dashboard ("this device is no longer protected");
nobody else sees it. Videos and online games use their list of
warda-lists and lists kept with Warda (internal/category/builtin.go,
also some social networks the downloaded lists leave out); they serve the
homework mode below. A category named in WARDA_CATEGORY_LISTS drops the
names kept with Warda. Job sites are allowed for everyone by default: a
business blocks them for the profile of the group of its workstations
(see Groups of devices).
Devices placed nowhere (those of visitors, new devices, until they are given to
someone or a group, and the addresses Warda does not know yet: a router
that forwards every query, a new IPv6 address) are protected as nobody by
default; they are never monitored, since they may be an adult's; the Protection settings
page can protect them like a child or a teenager instead
(PUT /api/v1/unknown-profile {"profile": "child"}).
The other lists are downloaded only when a profile blocks or monitors the
category, from warda-lists (see Lists). New domains hold about
a million names and block some new legitimate sites: turn them on only
where needed. Child sexual abuse material has no default source, on
purpose: such lists are only given to vetted organisations, and
warda-lists publishes none (its build refuses any source for csam).
This category applies only to the lists you give in
WARDA_CATEGORY_LISTS, which also replaces the list of any category, for
example WARDA_CATEGORY_LISTS="violence=/etc/warda/violence.txt,social="
(an empty value turns a category off).
Lists of hashes (CSAM) — from 0.8.0 (free, beta; catalogue
csam-hashes; internal/blocklist/hash.go). No list exists for Warda
today: the box is ready to apply one, and the owner of Warda has to
obtain it from an authorised body (the URL List of the Internet Watch
Foundation, or the body of the country of use; membership is contractual,
and its terms say how the list may be stored and refreshed). Until then
the category blocks nothing. Such lists are confidential: given to vetted
members only, never to be published nor readable on a device. So the
category also accepts a list of SHA-256 hashes of names, which the box
applies without anyone being able to read it from the box, the backups or
the logs:
- one hash per line, 64 hexadecimal characters (upper or lower case),
#comments allowed; each is the SHA-256 of a name in lower-case ASCII without the final dot (an internationalised name in itsxn--form); - a file whose entries are all hashes is a list of hashes; in a file that mixes names and hashes, the hash lines are ignored (counted as not understood), and the format of a plain list is read as before. A list of hashes works for any category, but is meant for this one;
- a name matches when its hash, or the hash of a parent at each label down
to two labels, is listed (
a.b.example.com,b.example.com,example.com; nevercom): an entry blocks its subdomains, as a domain of a plain list does. Names are hashed only while a list of hashes is loaded; - set as before:
WARDA_CATEGORY_LISTS="csam=/etc/warda/csam.txt"(a local file; anhttps://source works too, refreshed every hour); - a body that gives addresses of pages rather than names: only their host can be used, since a DNS filter cannot block a single page.
Protection settings, column List of the table of the categories (and the
list on a phone), says "Always blocked — list from an authorised body: none
loaded" or "… loaded, N entries" (names and hashes), never the content;
GET /api/v1/categories gives status.hashes for each category. From
0.8.0 a name of this category is never kept: the debug log says
blocked: csam only (it carried the name before), and the journal — so
the query log, the statistics and the SIEM export — records the name
csam.invalid instead of the name asked, with the origin
category:csam, behind a CNAME too and also when something that decides
earlier blocked it (a quarantine, the hours of Internet, a service, a
tunnel, a threat; its own origin is then kept). The block is still counted
in the security report.
Lists#
Every list Warda downloads by default comes from the repository
warda-dns/warda-lists, which gathers, checks and publishes them on its
branch dist, one file per list, one domain per line (# comments):
https://gitea.tips-of-mine.com/warda-dns/warda-lists/raw/branch/dist/<id>.txt.
| File | Used for |
|---|---|
base.txt |
Base blocklist: advertising and tracking (WARDA_LISTS) |
security.txt |
Security threats |
bypass.txt |
VPN, proxies and encrypted DNS |
newdomains.txt |
New domains |
adult.txt, violence.txt, hate.txt, drugs.txt, gambling.txt, piracy.txt, social.txt |
The categories of the same names |
video.txt, games.txt |
Videos and online games (with the lists kept with Warda) |
jobsearch.txt |
Job sites |
oui.tsv (from 0.8.5, not a list) |
The makers of the hardware addresses, downloaded once a day (see Network scan) |
The sources of each list and their licences are in LICENSES.md of
warda-lists; the lists are downloaded by each Warda, never shipped with
it. Each list is refreshed every hour (WARDA_LIST_REFRESH) with its
ETag, and a download that is not a list keeps the previous copy: no
entry, a web page, a list of Warda without its header, or, from 0.8.7, a
list that loses more than half of its entries at once (accepted when the
server still sends so small a copy 24 hours later; see
Upgrading to 0.8.7).
csam has no file and no default source (see above).
Two rhythms, not to mix up. warda-lists builds its lists again
every night at 03:17 UTC (and after a change of its sources): a list
changes about once a day. Each box asks every hour (WARDA_LIST_REFRESH,
1h by default, and up to 10 % more each time so that the boxes never
ask together) whether its lists changed, and downloads only those that
did: a new list reaches a box within about an hour of its build. From
0.7.11 the team of Warda has a module to verify these lists: a list is
measured before it is admitted, names are proposed to be added or
removed, and a person decides each one
(warda-lists,
warda-analyst).
Updating the lists now (free; internal/admin/listrefresh.go,
function lists-refresh-now of the catalogue). An administrator does not
have to wait for the next hourly check: the button Update the lists
now, on the dashboard under the line Base list and in the card
Updating the lists of Protection settings (which also shows the build date
of the base list and the last check of the box), checks at once the base
list and the lists of the categories in use, with their ETag as on the
schedule. The refresh runs in the background; the button shows
"Updating…", then the result:
| Result | Shown | Meaning |
|---|---|---|
ok |
Lists up to date | at least one list changed and is applied |
unchanged |
Already up to date | every list answered 304 Not Modified, or was sent again identical (a server without ETag) |
failed |
Failed: <reason> | a list could not be downloaded or was not a list; it keeps its previous copy (the reason is the first error, its addresses cut to their host, 200 characters at most) |
- One at a time, one a minute. A second click while a refresh runs answers that it is already running (the page then follows it); a new refresh is accepted a minute after the previous one started, so that a button pressed again and again never hammers the list servers. The scheduled refreshes go on as before (a refresh asked and a scheduled one never download together: they wait for each other). A refresh asked stops after 15 minutes, or with the service.
- Who. The accounts that change the system (
systemwritten: the administrators), with the session and CSRF token of the other actions. The accounts that only read the system see the state (and, on Protection settings, the dates) without the button. - Administration log.
lists.refreshwhen asked (with the account),lists.refreshedwhen it ends (result=ok,result=unchangedorresult=failed <reason>). Whatever started it (the hourly check or the button), each download that brings a list that changed is written, once its new rules are in use, aslists.updated(bysystem, detaillist=baseorlist=<category>), which the activity chart of the dashboard marks (see Events on the activity chart). - High availability. The button acts on the box whose page is open. The secondary box refreshes its own lists on its own schedule; to refresh it now, open its page (its own address) and press its button.
API:
| Route | Right | Answer |
|---|---|---|
GET /api/v1/lists/refresh |
system read |
{available, running, started, finished, result, error, last_check, generated, next_at}: last_check is the last time the box read its base list (scheduled or asked), generated the build time of the base list (# Generated:, absent when unknown), next_at when another refresh may be asked (absent: now) |
POST /api/v1/lists/refresh |
system written |
starts a refresh and answers the state (running: true); 409 {"error", "running": true, "refresh": {…}} while one runs; 429 {"error", "refresh": {…}} with Retry-After less than a minute after the last one |
GET /api/v1/system |
home read |
list_refresh: the same state, for the accounts that read the system |
The figures of a list (from 0.7.11, free;
internal/blocklist/manager.go, function list-names of the catalogue).
Each list of warda-lists tells two figures in its header: # Domains:,
its entries, and # Names:, the distinct names of its sources it stands
for (see
warda-lists). An
entry blocks its subdomains too: when example.com is listed, the build
drops ads.example.com from the file, and Warda blocks it all the same.
A tool that keeps one line per name (Pi-hole, AdGuard Home) counts both:
its counter is larger for the same names blocked. Warda reads # Names:
and # Generated: (the time of the build, UTC) and shows them on the
dashboard, card Services of the box, line Base list:
- when the list tells its names: "605,224 domains
blocked, covering 731,487 names of the source lists"
(the figures of the lists built on October 31, 2026; on
docs.warda-dns.com, those of the last build), and a small line under it: "Each entry also
blocks its subdomains: other tools count those names one by one. List
built on … ; this box last checked on …." — the first date is the build
of
warda-lists, the second the last check of this box; - otherwise, as before 0.7.11: "605,224 domains, updated …" (the date of
the last check). That is the line of a list built before
# Names:existed, of a list of someone else, and of a list whose names equal its entries.
What is read, and from where:
- only the first lines of the file (16 lines and 4096 bytes at most, the
comment lines it starts with), from the download and from the copy on
disk alike; a line written another way than
warda-listswrites it, or met twice, tells nothing: a figure is never guessed, and a figure smaller than the entries of the file is left out; - only for the lists of Warda: a source whose address is under the
address of the lists of Warda (
…/warda-lists/raw/branch/dist/). The same lines in a third-party list set inWARDA_LISTSnever change what is shown; GET /api/v1/system(every account that reads the dashboard), inservice.blocklist:names— the sum, over the sources that loaded, of the names of each when it tells them, of its entries otherwise; absent (0) while no source that loaded tells its names — andgenerated, the oldest build time known among the lists of Warda that loaded (absent when unknown). The accounts that see the addresses of the lists also get, for each source ofsources, its ownnames(0: unknown) andgenerated./healthzis unchanged: these two figures are never given without sign-in.
A first start, or an upgrade from a version that used other sources, may
find a list of warda-lists out of reach with no copy on disk yet. That
list then falls back on the source Warda used before it (HaGeZi Multi PRO
for base.txt, HaGeZi for security, bypass and newdomains, The Block
List Project for adult, drugs, gambling, piracy and social;
category.Fallbacks): downloaded once, read from its copy and logged
("list not downloaded yet: its previous source is used meanwhile", the
source shown with an error), and never again once the list itself is
downloaded, when its copy is deleted. A list you configure yourself has no
fallback.