Skip to content

Releases

v0.44.5

Choose a tag to compare

@github-actions github-actions released this 25 Oct 15:46

0.44.5

Who should upgrade

Every host on 0.44.0. 0.44.5 fixes the installer and the uninstaller,
start-up and shutdown, device identification by MAC address, backup and
restore, and the terminal UI. It changes no configuration schema.

Upgrade soon if:

  • you script installs or run them without a terminal: the installer now
    makes its refusals before it turns off the systemd-resolved stub or
    installs Warden, and its exit statuses say what happened (see
    Exit statuses);
  • a host serves many clients: the service unit raises the open-file limit,
    and the daemon asks for a larger UDP receive buffer;
  • you use Nodes: a list cached before 0.41 is no longer dropped from the
    node workspace, and a primary whose API address arrives late no longer
    exits at boot;
  • you uninstalled Warden and plan to install it again: a configuration that
    uninstall.sh kept is now adopted instead of refused.

A host on 0.41.x, 0.42.0 or 0.43.0 can upgrade straight to 0.44.5. Read the
0.44.0 notes
first: they cover what such a host must know before it upgrades, and
everything in them is new to it too.

How to upgrade

Fetch the installer fresh and run its upgrade mode:

curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade
  • From 0.41.x, upgrade in place with --upgrade too. Do not uninstall
    first.
  • From an unpacked bundle, run
    sudo ./scripts/install.sh --upgrade --binary ./warden in the bundle
    directory.
  • To preview, add --dry-run. get.sh now hands the flag to the installer
    once.
  • Over an existing install, get.sh now runs the installer's
    existing-install check before it replaces the installed bundle. If that
    check refuses, the installed bundle stays, and get.sh exits with the
    installer's status. Before, such a refused run left the new bundle in
    place and deleted the old one. A refusal from a later check, such as the
    upgrade check, the configuration check or the network check, still comes
    after the swap.
    When PURGE_VERSION pins a release whose installer predates these
    checks, get.sh skips them, prints one line that says so, and keeps the
    0.44.0 order.
  • If you run Warden under your own unit file instead of the shipped one,
    add LimitNOFILE=65536 to it. The shipped unit now sets it; a drop-in
    that sets a lower LimitNOFILE overrides it.

Exit statuses

install.sh --help now lists them:

Status Meaning
0 Success.
2 Invalid arguments. With --upgrade: a prerequisite of the upgrade check is missing or wrong, such as the dig tool or a setting; nothing was changed, and the message says which.
3 Fresh install: installed, but the service was still loading its blocklists when the wait ended, so DNS was not verified. Nothing failed: watch it with journalctl -u purge-warden -f. With --upgrade: the upgrade check refused the new version before anything was changed.
5 Installed, but the service stopped while it was starting, or DNS resolution or filtering failed verification.
other Refused or failed; the message says which.

A fresh install now waits up to 600 seconds, counted in real time, for the
first list download. A slow download ends with exit status 3 and the
commands to watch it finish, instead of exit status 5 and a message that
blamed the upstream resolver.

Before you upgrade

  • Scripts without a terminal. On a host where systemd-resolved holds
    port 53, an install without a terminal now refuses and names --yes.
    Before, it stopped at the question with a message that blamed another
    service. Add --yes to such scripts. The installer asks at the end of
    its preflight checks and turns the stub listener off only after its last
    refusal, so a refused install no longer has already turned off the
    systemd-resolved stub listener.
  • A configuration kept by uninstall.sh (without --purge).
    install.sh now adopts it: it checks it with the new binary and keeps it,
    and the --lan-cidr flag and the other first-install settings do not
    apply. A schema-4 configuration
    kept this way is refused until it is migrated: the refusal names the
    section "Schema-4 config kept by uninstall.sh" of
    docs/UPGRADE_RECOVERY.md, which migrates it offline with the bundle's
    binary. A schema-3 configuration kept this way has no migration route:
    run uninstall.sh --purge and install again. The installer checks a kept
    configuration after it has installed the dig and CA certificate
    packages it needs, so a refusal can leave those packages installed. To
    start from scratch instead, run uninstall.sh --purge first.
  • A stray backup directory. If an earlier release left
    /etc/purge-warden/backups on a host whose [backup] dir points
    elsewhere, check with ls -ld /etc/purge-warden/backups and move it out
    of /etc/purge-warden as root: the next backup would archive it.
  • A daemon home left by an older --purge. Hosts purged with
    uninstall.sh --purge from 0.44.0 or older may still have a
    /home/purge-warden (or /home/purge-shield) directory owned by a
    deleted account. The installer now warns about it. If you do not need its
    files, remove it with sudo rm -rf --one-file-system /home/purge-warden.

Changes

Installer

  • A host with another program on port 53 next to the systemd-resolved stub
    is refused before the stub is turned off. The refusal names that
    program's line in ss and says the stub change would not free it.
  • A configuration path that is a dangling link or a directory is refused
    before the installer changes anything.
  • A configuration kept by uninstall.sh that fails the new check names its
    schema, says that --upgrade cannot run on that host, and names
    uninstall.sh --purge with what it deletes. The exit status stays 6.
  • The network check before an install now tests lists.purge.cc, which the
    first start needs for the blocklists, instead of a distribution mirror.
  • --dry-run no longer prints success marks for steps it skipped. A
    fresh-install preview ends with Dry run complete, and shows the home and
    token steps instead of warning that the user and the configuration are
    missing.
  • The refusal over an existing install names a command that works where you
    run it: the get.purge.cc one-liner after get.sh,
    --upgrade --binary <bundle directory>/warden in a bundle. An incomplete install names uninstall.sh (which keeps the
    configuration for the next install) instead of --upgrade, which refuses
    it.
  • Hints printed during a get.sh run name the installed bundle, not the
    temporary copy that get.sh deletes when it ends.
  • When the installer exits early, its last lines still reach the screen and
    the log.
  • The check for the systemd-resolved stub no longer misses it from time to
    time. Before, an install could stop with port 53 is already in use on a
    host where only the stub held the port.
  • install.sh --help says what --upgrade does and lists the exit
    statuses.

Uninstaller

  • uninstall.sh --restore-resolved points /etc/resolv.conf back at the
    systemd-resolved stub when it is the absolute link to
    /run/systemd/resolve/resolv.conf that the installer writes and the stub
    listens after the restart. Otherwise it warns and leaves the link.
  • uninstall.sh --purge removes the daemon home that install.sh created
    (/home/purge-warden or /home/purge-shield, owned by the daemon user).
    It leaves any other home in place with a warning, and for a home outside
    those two paths says to remove it by hand if it was the daemon's.
  • uninstall.sh --purge run from the installed bundle says that the bundle
    in /usr/local/lib/purge-warden remains and prints the command to remove
    it.
  • Without --purge, uninstall.sh refuses to keep a configuration in the
    middle of a migration or a relocation: the next install would refuse it,
    and the binary that finishes the step would be gone. The refusal names the
    command that prints the next step.
  • uninstall.sh removes the .s6-old copies that an interrupted upgrade left
    next to the binary and the unit files. They blocked a later --upgrade.
  • On a host with firewalld, uninstall.sh says when DNS is still allowed
    and prints the commands to close it:
    sudo firewall-cmd --permanent --remove-service=dns && sudo firewall-cmd --reload.
  • --dry-run no longer reports removals it only previewed.
  • The --purge help and the removal plan name where each token lives: the
    plaintext IPC token and the cluster token under /var/lib/purge-warden,
    the token hashes and secrets.toml under /etc/purge-warden.

Start-up, reload and shutdown

  • A standalone host (no cluster) keeps serving DNS when the node corpus
    store cannot open, and logs an error. It runs without the node corpus:
    list bodies held only in a parser cache need a download. A stray entry in
    the corpus cache no longer stops a start, a reload or a node command. A
    host with a cluster still refuses to start.
  • A change to the global [local_dns] section applies on reload. Before, it
    needed a restart, and every later reload was refused until then.
  • Messages for a change that needs a restart now say that the daemon refuses
    every later reload until that restart. In the terminal UI, a Tracking save
    that changes the retention or the log mode shows this as a warning.
  • Any entry in packs/ that is not a pack file (<id>.txt), such as an
    editor swap file, a backup file or a subdirectory, is ignored with a
    warning instead of failing the next start. warden status lists such
    entries. Backups leave them out and print the same warning.
  • The boot refusal for a configuration that does not load names the next
    step: lint, restore (when an archive exists) and restart. The refusals for a relocation in
    progress, a secrets file with the wrong mode and the secondary bootstrap
    end with ...
Read more

v0.44.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 14:49

0.44.0

Who should upgrade

Every host on 0.41.x, 0.42.0 or 0.43.0. 0.42.0 and 0.43.0 were
pre-releases, and get.purge.cc served 0.41.0 as its stable version, so most
hosts come straight from 0.41.0. If yours does, everything in 0.42.0 and
0.43.0 is new to you too: read the 0.42.0 and
0.43.0 notes first. The notes below cover what changed since
0.43.0 and what a 0.41.0 host must know before it upgrades.

Upgrade a 0.42.0 or 0.43.0 host soon if Warden's files are on btrfs, or on
another filesystem that can renumber its device at boot (ZFS, NFS, overlayfs,
device-mapper). On those hosts, a reboot after a policy change could stop the
daemon with receipt identity mismatch and leave DNS down. 0.44.0 no
longer compares the device number. A host already in that state can upgrade:
see From a failed daemon.

How to upgrade

Fetch the installer fresh and run its upgrade mode:

curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade
  • Do not rerun a copy of get.sh saved from 0.41.0 or 0.42.0. The bundle
    ships docs/UPGRADE_RECOVERY.md, and those copies refuse it with
    the bundle contains an unexpected path. They install nothing.
  • To preview the upgrade, add --dry-run:
    curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade --dry-run.
    The preview now changes nothing. Before, --dry-run on the command line
    replaced the installed bundle.
  • From an unpacked bundle, run
    sudo ./scripts/install.sh --upgrade --binary ./warden in the bundle
    directory.
  • Source installs: build with cargo build --release, then run
    sudo ./scripts/install.sh --upgrade from the checkout. make install is
    for a first install only and skips the configuration check. make upgrade
    from a 0.43.0 or older tree overwrites the warden wrapper and skips the
    check. The daemon kept running the old version. To fix such a host, run
    sudo ./scripts/install.sh --upgrade from the new tree; it upgrades the
    daemon and puts the wrapper back. make upgrade from the 0.44.0 tree
    refuses such a host and changes nothing.
  • get.purge.cc publishes the bundle for x86_64 only. On aarch64, get.sh
    stops with download failed and points at building from source. Build as
    BUILDING.md describes, then run
    sudo ./scripts/install.sh --upgrade --binary <path> from the checkout, or
    sudo ./scripts/install.sh --upgrade --build-from-source.

The upgrade still runs as one transaction: it checks the configuration with
the new binary first, migrates a 0.41 configuration, starts the new version,
and checks that it answers and blocks. If a step fails, it puts the old
version back. If it ends with exit status 75 or RECOVERY REQUIRED, or a
crash or power loss stopped it, follow docs/UPGRADE_RECOVERY.md. The file
ships in the bundle, under /usr/local/lib/purge-warden/docs/ for a
get.purge.cc install.

From a failed daemon

On a 0.42.0 or 0.43.0 host, the upgrade now also accepts a daemon that
systemd reports as failed, so you can upgrade a host whose installed
version no longer starts. A 0.41.x host still needs a running daemon.

  • activating means systemd is still retrying: wait until
    systemctl is-active purge-warden.service prints active or failed.
  • inactive means the daemon was stopped: start it, then upgrade.
  • A host that resolves names through its own Warden resolves nothing while
    the daemon is down, so the download fails. Add a temporary nameserver
    line to /etc/resolv.conf for the upgrade, and remove it afterwards.
  • If the new version fails its check, the upgrade puts the old version back,
    starts it once and exits with the exact old ELF and unit were restored.

See "Upgrading a failed daemon" in docs/UPGRADE_RECOVERY.md.

Cluster secondaries on 0.41

A 0.41 cluster secondary still cannot be upgraded in place. The upgrade
refuses it with nothing changed. Its cluster_local_policy_conflict finding,
listed by the command the upgrade prints
(<candidate-elf> --config <master> migrate v4-to-v5 --check --json), now
gives the steps. Take the node out of the cluster, upgrade both nodes, then
join again:

  1. On the secondary, still on 0.41, run warden cluster leave. If it asks
    for a resolver, run warden cluster leave --upstream <addr:port>.
  2. Upgrade the secondary as a standalone node.
  3. Upgrade the primary.
  4. On the primary, run
    warden cluster create --migrate-legacy --san <primary address>, then
    warden cluster apply --preview-id <id>, then
    systemctl restart purge-warden. If the primary's API is off or listens
    on loopback, add --api-listen <addr:port> with an address the secondary
    can reach.
  5. On the primary, run warden cluster invite.
  6. On the secondary, run
    warden cluster join --peer <primary https origin> --invitation-file <file>,
    then warden cluster apply --preview-id <id>, then restart it.

See "Cluster secondaries" in docs/UPGRADE_RECOVERY.md.

Before you upgrade

  • Wildcard, regex and $important rules (0.41). Configuration schema 5
    reads some of these rules differently. If the check finds one, the upgrade
    stops with nothing changed and prints the command that lists the findings.
    You can now accept them: list the findings with the command the upgrade
    prints (<candidate-elf> --config <master> migrate v4-to-v5 --check --json),
    write a choices file, and run the upgrade again with it:
    curl -fsSL https://get.purge.cc | sudo WARDEN_UPGRADE_MIGRATION_CHOICES=/root/choices.json sh -s -- --upgrade.
    Put the variable after sudo, not before it. A finding that allows only
    defer cannot be accepted. See "Migration findings" in
    docs/UPGRADE_RECOVERY.md.
  • IP blocklists. If [ip_blocklists] is enabled, every source must be a
    public https:// URL, with no user name or password and no private or
    loopback address. 0.41 skipped such sources with a warning, so they
    filtered nothing; 0.42.0 and 0.43.0 refused to start. warden config lint
    and the upgrade check now refuse them, and the upgrade stops with nothing
    changed. Change each such source to a public https:// URL without a
    user name or password, or remove it, first.
  • Backups made by 0.41. 0.44.0 restores only schema-5 archives. It
    refuses an archive from 0.41 or earlier with a message such as
    schema-4 archive (Warden 0.41 or earlier); live config untouched and
    explains how to copy its settings by hand. If you may need one of those
    archives, restore it before you upgrade. Run warden config backup once
    the upgrade is done.
  • Disk space. Each policy write keeps undo data in the configuration
    directory for at least 24 hours. It is now capped at 2 GiB per
    configuration. A write that would pass the cap is refused with
    UndoStoreFull until older data expires. The REST API answers such a
    refusal with 429 instead of 503.
  • Anti-bypass is now off by default. Up to 0.43.0 it was on by default
    but blocked nothing without extra_domains, so filtering does not change. A
    section that lists extra_domains keeps it on. enabled = true with no
    domains still warns. To stop the warning, list the resolver names to
    refuse in extra_domains, or set enabled = false.
    warden lists add services/resolvers adds a resolver list as an ordinary
    block list instead; it does not feed anti-bypass.

Changes

Upgrade and rollback

  • The upgrade saves the publication store
    (.warden-cluster-publications in /var/lib/purge-warden) before the new
    version starts, and puts it back if the upgrade rolls back. It prints the
    copy as publication store snapshot: <dir>, under
    /var/tmp/purge-warden-store.*. On a node with the cluster enabled where
    the new version published a newer policy epoch, the upgrade does not put
    the store back: it exits 75 with RECOVERY REQUIRED, and you follow end
    state c in docs/UPGRADE_RECOVERY.md. See "Publication store snapshot"
    in docs/UPGRADE_RECOVERY.md.
  • When the migration check blocks, the message now names
    WARDEN_UPGRADE_MIGRATION_CHOICES and the "Migration findings" section.
  • A configuration with a [[retired]] entry dated in the past now upgrades.
    The check no longer reports the date as being in the future.
  • .s6-old files left by a killed upgrade still make the next upgrade
    refuse with nothing changed. The steps it prints now include putting the
    publication store back.

Start-up and reload

  • systemctl reload during start-up no longer stops the daemon. A reload
    received while the daemon starts is applied once DNS serves. Before, it
    ended the process and systemd did not restart it.
  • If the REST API certificate or key cannot be read at start, Warden logs
    the error and serves DNS with the REST API off, instead of restarting in a
    loop. A primary created with warden cluster create still refuses to
    start.
  • Nodes start-up steps that fail, for example on a busy configuration lock
    or a damaged Nodes state, no longer stop a daemon that serves DNS. They are
    retried every 2 seconds and shown as Problem: lines in
    warden node status until they succeed.
  • A Nodes listener that cannot be restored at start (address gone, port
    taken) is skipped and shown as a Problem: line in warden node status.
    DNS and the other listeners keep serving.
  • warden start --safe-mode no longer exits when config.toml is invalid.
  • A primary or standalone host now starts when a list has no downloaded copy
    yet (for example a list added while the daemon was stopped), or when its
    node-corpus bookkeeping fails. It logs the problem and serves DNS with the
    lists it has, instead of restarting in a loop.
  • An ...
Read more

v0.43.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 01:12

Superseded by v0.44.0: upgrade with https://get.purge.cc.

0.43.0

Coming from 0.41.0

If you upgrade from 0.41.0, everything in 0.42.0 is new to you too: Warden
Nodes (beta), the reworked terminal UI, and the new operator rules with
configuration schema 5. Read the 0.42.0 notes for those
changes. The notes below cover what is new since 0.42.0, and how the
upgrade from 0.41.0 works now.

Upgrading

Upgrade an existing install with the installer's upgrade mode:

curl -fsSL https://get.purge.cc | sudo sh -s -- --upgrade

or sudo ./scripts/install.sh --upgrade from an unpacked bundle or a
checkout. Without --upgrade the installer refuses a host that already has
Warden and tells you to rerun it with the flag.

0.41.0 keeps its configuration at schema 4, and 0.43.0 needs schema 5. The
upgrade now migrates the configuration inside its own transaction, so the
manual warden migrate v4-to-v5 step that the 0.42.0 notes asked for is not
needed on this path. In order, the upgrade:

  • checks the configuration with the new binary, before it changes anything;
  • stops the daemon and the scheduled backup, and keeps the old binary and
    service unit;
  • plans and applies the migration;
  • installs the new binary and unit, starts them, and checks that the new
    daemon answers and blocks;
  • only then finalizes the migration.

If the check finds something that blocks the migration, the upgrade stops
before it changes anything and prints the command that lists the findings. A
failure, or a Ctrl-C, a hangup or a plain kill (SIGTERM) before the final
step, rolls the configuration back and starts 0.41.0 again. The migration
moves the allow and deny rules you added in 0.41.0 into Custom Lists. The
old allow and deny commands now refuse to write: create a Custom List with
warden custom-list and mount it on a profile with warden profile mount.

The health check expects the new daemon to answer on the loopback address,
resolve one name and block another with a 0.0.0.0 answer. If your setup
answers blocked names in another way, or blocks everything, read "How the
upgrade runs" in docs/UPGRADE_RECOVERY.md before you upgrade. An upgrade
that fails the check rolls back.

If the upgrade ends with exit status 75 (most of these messages say
RECOVERY REQUIRED), or was stopped by a crash or a power loss, follow
docs/UPGRADE_RECOVERY.md. It ships in the bundle as
docs/UPGRADE_RECOVERY.md, under /usr/local/lib/purge-warden/docs/ for a
get.purge.cc install. Some installer messages name the section to read;
otherwise start at "End states after exit 75", or at "Killed or crashed
upgrades" after a crash or power loss. The manual warden migrate v4-to-v5
commands are described there as a recovery tool, not as an upgrade step. A
file left with the .s6-old suffix by a killed upgrade makes the next
upgrade refuse before it changes anything, with the steps to recover.

Also in the upgrade:

  • A host already on 0.42.0 has schema 5, so the upgrade runs no migration.
    It replaces the binary and the units.
  • --upgrade no longer needs a LAN range (--lan-cidr), and its plan no
    longer lists the settings that only a fresh install uses (LAN range,
    listen address, upstream, lists, run user).
  • Starting 0.43.0 on a schema 4 configuration, or running
    warden config lint on one, now says that install.sh --upgrade
    migrates it.
  • If a signal stops the installer after the upgrade has committed, it says
    so and exits with status 4. The new version is installed and running; run
    the same command again to finish the remaining steps.
  • The upgrade keeps your configuration where it is. A host installed before
    0.43.0 keeps /var/lib/purge-warden/config.toml; see
    Configuration under /etc/purge-warden.
  • On such a host the installer prepares the backups directory as the
    purge-warden user. A backups directory that is a symbolic link is
    left as it is, with a warning.

Before you downgrade

  • Open the dashboard once (warden dashboard). If it shows Policy recovery,
    press r (Recover) until the change is committed or aborted. The 0.42.0
    dashboard cannot read the recovery record that 0.43.0 writes for an
    interrupted batch of Query Log rules.
  • If you moved the configuration with warden config relocate, move it back
    first with config relocate --reverse, run the same way as the move (see
    below). Releases before 0.43.0 do not know the move.
  • 0.41.0 cannot read a schema 5 configuration. Once the upgrade has
    finalized the migration, a 0.41.0 binary cannot start on it.

Query Log: hold rules, apply them together

In the Query Log, Enter on a row opens the rule dialog. Its Hold rule button
now holds an ALLOW or DENY rule for that domain on the Custom Lists you
pick, instead of opening a plan for that one domain. A "HELD RULES — NOT
ACTIVE YET" card shows how many rules are waiting. You can hold up to 32
rule-and-list pairs at a time, fewer if the daemon allows fewer, for one or
more domains, on the same list or on different lists.

Press v to review them. The held rules are a table with ACTION, DOMAIN and
LIST columns: ←/→ pick a cell, and e or a click on the selected cell edits
the action, the domain or the lists. An edit is checked like a new hold, and
Esc drops it. Delete or Remove takes one rule out, Discard all drops them
all after you confirm, and Review all shows a single plan. Apply saves every
held rule as one change with one reload, instead of one apply per domain.

Held rules do nothing until you apply them, and they live only in the open
dashboard session: quitting discards them, after asking first. An Apply
already submitted may still complete; the next warden dashboard shows its
outcome. If an apply fails or is cancelled, every held rule stays held.
Creating a New List from the picker is still a separate change with its own
plan and Apply. On a read-only node, apply rules on the primary.

Configuration under /etc/purge-warden

A fresh install, from the installer or from warden init without
--config, now creates the configuration at
/etc/purge-warden/config.toml. The files it includes, such as Custom List
packs and list files imported from this machine, sit beside it. Downloaded
list caches, data and node state stay under /var/lib/purge-warden, and the
new configuration sets
[backup] dir = "/var/lib/purge-warden/backups" for backup archives.

An existing host keeps /var/lib/purge-warden/config.toml, and no second
configuration is created. warden init refuses to create one under /etc
while the old one exists.

Moving an existing configuration: warden config relocate

warden config relocate moves the configuration of a host installed before
0.43.0 from /var/lib/purge-warden to /etc/purge-warden. Moving is
optional, and the upgrade never does it for you.

  • It runs offline and as root. Stop purge-warden and
    purge-warden-backup.timer first, and run the real binary,
    /usr/local/libexec/purge-warden/warden. The warden command on your
    PATH runs as the service user, which the move refuses. --config is
    refused too: the two paths are fixed.
  • Run warden config backup first. The move also refuses a configuration
    without an absolute [backup] dir.
  • --dry-run runs every check and prints the plan, and moves nothing.
  • Every file moves by rename, so it keeps its owner and mode. /etc and
    /var/lib/purge-warden must be on the same filesystem and mount;
    otherwise the move refuses and changes nothing.
  • Node identity and cluster pairing survive the move. List files imported
    from this machine move with the configuration; downloaded list caches,
    state and backup archives stay in /var/lib/purge-warden.
  • When restorecon is installed, the move relabels the new location.
  • A run that stops part way prints the one command that rolls it back, and
    the daemon refuses to start until that command has run.
  • --reverse moves the configuration back to /var/lib/purge-warden.

After the move, start purge-warden and the backup timer again, and wait
until warden status answers. warden config relocate --help lists the
exit codes.

Rewrite and negative answers

A rewritten answer that holds records starts with a CNAME from the name the
client asked for to the rewrite target. Two things change:

  • The CNAME always names the target you configured, the one policy checked.
    Before, it took the name from the first upstream record. Fresh, cached and
    stale answers behave the same.
  • A rewrite whose upstream chain leads back to the name the client asked for
    is refused and answered as blocked. The rewrite step also counts toward
    the CNAME chain limit, [cache] cname_max_depth.

An NXDOMAIN answer whose upstream answer holds CNAME records now keeps them,
with the NXDOMAIN code and an SOA record. Before, the answer section was
emptied. For a rewrite, the CNAME from the asked name to the target is kept
too. An NXDOMAIN or NODATA answer with no records still has an empty answer
section, with no rewrite CNAME.

Nodes

On a primary, a change that touches only policy now applies without
rebuilding the list corpus. This holds when the lists are unchanged and IP
blocklists are off before and after the change. Turning IP blocklists on or
off, or changing a list, still rebuilds. If the commit fails after the new
policy is swapped in, the change is not reported as applied.

Backups

  • On a node whose configuration is still under /var/lib/purge-warden,
    warden config backup refused list files that the node also hard-links
    into its list corpus. It now archives them, and still refuses any other
    hard link.
  • On Fedora 44 every scheduled back...
Read more

v0.42.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 09:30

Superseded by v0.44.0: upgrade with https://get.purge.cc.

0.42.0

Warden Nodes — policy and list synchronization (BETA)

Warden can now run as a cooperating set of nodes instead of a single
resolver. One node acts as the primary; the others join it, authenticate,
and receive its policy and blocklist state, so a change made once is
reflected everywhere without hand-copying configuration between machines.

Onboarding is guided: the primary issues a short-lived association token,
the joining node presents it, and the pair establishes an authenticated,
certificate-pinned channel. Nodes are durable — they survive restarts and
reappear with their last known state rather than vanishing from the
cluster.

This is a beta. It is off unless you configure it, a single-node
install is completely unaffected, and the synchronization protocol may
still change incompatibly between releases. Try it on machines you can
afford to re-provision, and report what breaks.

Reworked terminal UI

The Dashboard and Query Log have been rebuilt around the layouts operators
actually kept open.

  • The Dashboard presents block rate, traffic, query types, upstream and
    memory state as consistent cards with explicit labels, responsive
    scrolling, and hour/date inspection — and keeps real warnings in the
    header instead of hiding them behind decoration.
  • The Query Log has one filter row (Domain, Client, Period, Blocked, and
    an Advanced view), a single-key picker, a 3-hour preset, and shared
    modal styling throughout. Long error messages no longer destroy your
    in-progress form input; drafts survive.
  • Device labels are now persistent, named categories you can reorder from
    the Configuration view, and device dialogs follow the same layout rules
    as the rest of the interface.
  • Polling and disk writes moved off the input event loop, so the
    interface stays responsive while it refreshes.

Safer operator rules and configuration changes

The policy engine behind operator-defined rules has been reworked end to
end, with an emphasis on never leaving the daemon in a half-written state.

  • Policy writes are transactional: a change either applies completely or
    not at all, and a failed write cannot strand a partial rule set.
  • The configuration schema has moved forward (v4 → v5). The migration is
    deterministic and keeps a backup; a daemon that cannot migrate refuses to
    start on the unknown schema rather than guessing.
  • Reloads are generation-safe: a new configuration is validated as a
    complete generation before it replaces the active one, so a broken
    reload keeps the last good policy serving.
  • Cluster policy artifacts are coherent across nodes: every member of a
    synchronized set evaluates the same policy generation.

Existing v4 configurations need one manual step before the new daemon will
start: run warden migrate v4-to-v5 --check to preview the migration, then
apply it. The daemon deliberately refuses to boot on a v4 file instead of
guessing at your intent.

Fixes

  • Draft text in TUI forms is preserved across long profile errors,
    refreshes, and view changes.
  • DoH upstreams that require HTTP/2 now work; previously such providers
    answered every query with a failure while the daemon reported healthy.
  • The security update to the HTTP/2 dependency (h2 0.4.16) is included.

v0.41.0

Choose a tag to compare

@github-actions github-actions released this 07 Sep 14:59

0.41.0

List refresh integrity

List updates now take a more deliberate path from download to the active
corpus. The aim is to keep a working list set available while an update is
being checked, and to refuse incomplete or inconsistent data before it can
replace that set.

Refreshes publish as complete generations

Each configured source is resolved to one canonical identity before refresh.
Conflicting aliases are rejected during configuration checks and strict
startup. A reload that finds a conflict keeps the active configuration rather
than replacing it with an invalid one.

Cache data is admitted and published as a complete, validated generation, not
as a mixture of old and new source bodies. A refresh checks staged input before
it becomes active. If a refresh is refused or fails, an already accepted corpus
remains available instead of serving a partial update. Storage errors during
staging also prevent that generation from being published.

The refresh status distinguishes a degraded refresh from a healthy one and
keeps retrying within bounded work. Forced refresh requests for the same list
manager join existing work instead of starting competing writers.

Lower-peak refresh path, with explicit limits

With a cache directory enabled, decoded HTTP data streams into a private
disk-backed generation. The parser and shard builder then work from staged
data, and publication waits for complete validation. This avoids retaining a
whole downloaded body and a whole replacement corpus on the normal refresh
path at the same time.

Input bodies, entries, parser lines, and format detection all have limits.
Size calculations fail safely on overflow, and staged content is checked again
before publication. URLs with embedded credentials are rejected before cache
metadata is accepted, while cache identity continues to use the exact resolved
URL.

This is bounded streaming, not a fixed process-memory promise. Peak memory
still depends on the installed domain set, configured limits, allocator
behavior, and operating-system cache. Running without a cache directory keeps
a supported, memory-resident fallback bounded by the configured body limit,
but it is not the lower-peak refresh mode.

Safer configuration changes and recovery

Configuration writes are serialized so concurrent commands do not overwrite
one another. The configuration format upgrade is transactional and
crash-safe, with recovery controls for an interrupted change. Existing
configurations retain their active state if validation cannot complete.

Dependency maintenance

The HTTP/2 implementation was updated to close RUSTSEC-2026-0258, which could
allow a peer to consume resources with an unbounded stream of empty DATA
frames.

Together, these changes make list refreshes easier to reason about: updates
become visible only as complete validated results, failures preserve the last
accepted data where available, and status reports show when refresh work needs
attention.