Skip to content

v0.3.0 — HTTP blocklist source

Choose a tag to compare

@bcrisp4 bcrisp4 released this 21 May 06:40
· 34 commits to main since this release

Highlights

Adds a polite, self-refreshing HTTP blocklist source so operators no longer need to bake lists into the container image or babysit git pull/SIGHUP. The default container now fetches hagezi pro.txt at startup, caches it to disk, and refreshes every 24h with conditional GET.

What's new

  • type: http blocklist source — fetches lists from any HTTP(S) URL with conditional GET (ETag / If-Modified-Since). Configurable global refresh interval (blocklists.refresh_interval, default 24h).
  • On-disk persistent cache at blocklists.cache_dir (default /var/cache/bns/blocklists). Bodies + sidecar metadata written atomically; readers never observe a partial write. Survives restarts.
  • Bootstrap dialer — fetcher resolves URL hostnames via configured upstream IPs directly, bypassing the system stub. BNS can fetch its own lists even when it's the sole resolver on the LAN.
  • Always fail-open — HTTP fetch failures never block DNS service. A bns_blocklist_last_success_timestamp_seconds{source} gauge supports staleness alerts.
  • Per-source observability — three new metric families:
    • bns_blocklist_fetch_total{source,outcome} (success / not_modified / failure)
    • bns_blocklist_last_success_timestamp_seconds{source}
    • bns_blocklist_entries_by_source{source}
  • Required name field on every blocklist source — used as the {source="..."} label on every bns_blocklist_* metric. Validation rejects missing or duplicate names at startup.
  • SIGHUP now does both — reload disk state (file-source edits) and trigger an immediate fetcher cycle (HTTP sources).

Breaking changes

  • --blocklist CLI flag removed. Use YAML (-c file.yaml) for blocklist source configuration. The flag is incompatible with the new required name field; YAML is the canonical declaration form.
  • Container no longer bakes the hagezi list. Cold start with no cache volume serves DNS without blocking for a few seconds while the first fetch lands. Mount a named volume at /var/cache/bns to preserve cache across restarts:
    docker volume create bns-cache
    docker run -v bns-cache:/var/cache/bns ghcr.io/bcrisp4/bns:0.3.0
  • HAGEZI_TAG Dockerfile build arg dropped.

Config schema

blocklists:
  refresh_interval: 24h
  cache_dir: /var/cache/bns/blocklists
  sources:
    - type: http
      name: hagezi-pro
      url: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/domains/pro.txt
    - type: file
      name: custom-blocklist
      path: /etc/bns/custom-blocklist.txt

Container images

Multi-arch (linux/amd64, linux/arm64) at ghcr.io/bcrisp4/bns:0.3.0, :0.3, :latest.

Spec + plan

  • Design: docs/specs/2026-05-21-bns-http-blocklist-source-design.md
  • Implementation plan: docs/plans/2026-05-21-bns-http-blocklist-source-implementation.md
  • 16 TDD tasks plus a simplify pass and a code-review-driven fix-up.