Reputation Feeds
What they are
Public IP reputation feeds (Spamhaus DROP, FireHOL, AbuseIPDB exports) list addresses observed attacking other people's servers. EzyShield can pull them in as an extra signal — or drop them outright at the firewall — while keeping them strictly separated from everything your own server observed.
# /etc/ezyshield/config.yaml
feeds:
- name: spamhaus-drop
url: https://www.spamhaus.org/drop/drop.txt
format: cidr
refresh_interval: 12h
action: observe # or: blockFormats: plain (one IP per line), cidr (IP or prefix per line, ;/# comments — Spamhaus DROP and FireHOL), abuseipdb (plain list export). Respect each feed's usage policy — the annotated example in configs/config.yaml carries per-feed notes (Spamhaus asks for at most two fetches a day; AbuseIPDB exports require an account).
observe vs block
action: observe(default): entries live only in the daemon's memory as a reputation flag. When an IP from a feed also trips your local rules, its score gets a +15 boost and the verdict reason carries[reputation:<feed>]. A feed alone never creates a verdict, a strike, or a ban — someone else's report is corroboration, not proof.action: block: entries are additionally dropped at the edge of the ezyshield nftables table, in a dedicated set.
Set separation — feeds are not bans
Feed entries never touch the strike ladder, never appear in ezyshield list, and never write rows to the ban store. They live in their own nftables sets (blocked_feeds / blocked_feeds6), reconciled wholesale on every refresh with a per-element timeout (default 2× the refresh interval — a dead feed drains on its own instead of blocking forever). Your strike history stays purely behavioral: what your server observed, with evidence.
Each refresh writes one audit-log summary row (feed_refresh: entries, skipped-by-guardrails, removed) — never one row per IP.
Why feeds can never bypass the allowlist
A feed is remote data that somebody else controls — treat it as potentially poisoned. EzyShield defends in layers:
- At parse time (per fetch): only strict IP/CIDR parsing; private, loopback, link-local and reserved ranges are always dropped; 10MiB / 4KiB / entry-count caps; https-only including redirects; a failed or garbage refresh keeps the last known-good set.
- Before any apply: every entry is filtered against your allowlist and admin CIDRs, your live SSH peers, and shared CDN ranges — in both overlap directions, so a broad prefix covering your admin host is dropped just like the host itself.
- In the firewall: the allowlist accept rules sit before the feed drop rules in every chain.
armed: false(dry-run) writes nothing to the firewall.
Operating
ezyshield feeds status # per feed: last/next refresh, entries, skipped
ezyshield feeds refresh # re-fetch every feed now
ezyshield feeds refresh spamhaus-dropA non-zero "skipped" count means the guardrails filtered entries — on a reputable feed that is unusual and worth a look (it is also logged as a possible-poisoning warning).