• v0.0.1 79e7025fae

    v0.0.1 Pre-release

    Robin released this 2026-08-14 19:11:16 +02:00 | 153 commits to main since this release

    The first real release of the standalone agent.

    It tails the log inputs you declare, evaluates your rules, applies
    sanctions to the machine's own nftables, and keeps every decision in a
    local store that survives restarts. One binary, plain YAML, no database
    daemon, no external service on the machine it protects. shield ships
    alongside for status, bans, why, unban, exempt and replay.

    Install

    curl -fsSLO https://git.lrob.net/Shieldlist/shieldlist-agent/releases/download/v0.0.1/install.sh
    less install.sh          # one file of sh — read it before running it
    sh install.sh
    

    It enforces nothing until you say so

    A fresh install writes a starter configuration in detect-only: every
    rule records what it would have done, and nftables is never touched.
    Run it beside fail2ban, CrowdSec or whatever already guards the machine,
    read a day of it —

    shield status               # what it would be holding
    shield bans                 # which addresses, by which rule
    shield why 203.0.113.9      # the log lines that convicted one of them
    

    — then set state: on in /etc/shieldlist/agent.yaml and restart.

    Exempt yourself first, in /etc/shieldlist/exemptions.yaml.

    What is in it

    • Detection: literal-prefiltered RE2 parsers, rules that score
      weighted evidence across parsers within a window, negative weights so
      good traffic can exculpate, distinct counting, group_by ip and
      range:/n.
    • Sanctions: duration ladders that climb only when an offender
      returns after a ban ran out, port scopes per rung, decay measured from
      a ban's end, exemptions (with until:), trust weights on origins.
    • Enforcement: one inet table, prerouting, ct direction original
      so machine-initiated replies are spared; persist-first, so losing the
      agent never unbans; a restart rebuilds the data plane from the store
      in the background while the agent already watches.
    • Reading the past: shieldlist-agent -dry-run 24h [-rule NAME]
      judges by window and ban duration — a crossing counts only if the
      sanction it earns would still be in force now.
    • Bounds: a memory ceiling the agent holds itself to (half the
      machine by default), measured per-rule and per-parser cost, ordered
      shedding, and figures for all of it in shield stats.

    Proven on a 2-core VPS: ~68k lines/s at one core, and 5.1M distinct
    addresses banned without losing one. What nothing can bound — nftables
    set memory is kernel memory — is written down in docs/RESOURCES.md.

    It checks the kernel before trusting it

    At startup the agent builds its own table under a throwaway name, with
    no hook — so nothing in it is ever evaluated against a packet — puts
    elements in it with timeouts and concatenated address·port keys, and
    removes it again. What it proves is what the agent will actually ask
    for, because the probe renders the same script.

    A kernel that refuses gc-interval gets a warning and a working agent;
    an expired element stops matching traffic whether or not it has been
    collected. A kernel that refuses anything else stops the agent at
    startup with one sentence naming what it refused, rather than a parse
    error out of a child process in the middle of an attack.
    shieldlist-agent -t runs the probe too — that is where an operator
    asks whether a machine can enforce, and the only place an agent in
    detect-only would ever find out.

    Verified on Debian 12 (kernel 6.1, nft 1.0.6) and Debian 13 (kernel
    6.12, nft 1.1.3).

    Its log is where you will look for it

    Under systemd the log goes to the journal, which is right — but
    /var/log is the first place anyone looks after starting a security
    daemon, and fail2ban and CrowdSec both write a file there. So does this
    now: log_file: /var/log/shieldlist/agent.log, set in the shipped
    configuration, with the same lines as journalctl -u shieldlist-agent.

    No logrotate snippet ships with it. The agent identifies the file by
    (device, inode) like every other file it follows, notices when logrotate
    has renamed it away, and reopens.

    Pre-1.0, and honest about it

    • Releases are not signed. The checksums are served from the same
      host as the binaries: they prove the download was not corrupted, and
      nothing more. Signing is an open decision (SPEC §11).
    • The configuration format may still change.
    • Shipped rules cover sshd only. Rules for web, mail and panels are
      being written; docs/CONFIG.md and the wiki's Writing rules page
      are how to write your own meanwhile.
    • The central controller does not exist yet. Standalone is a mode, not a
      fork: the same files carry over when it does.

    Requires Linux with nftables. Builds for amd64, arm64, armv7 and
    riscv64; no cgo.

    Downloads