RegBan is a small fail2ban-style tool that reads command output, extracts IP
addresses with regular expressions, scores repeated matches, and adds offenders
to nftables sets for a configurable amount of time.
It is intentionally narrow. RegBan does not watch files itself, does not manage
firewall rules, and does not wake up later to unban addresses. It expects other
Unix tools to stream logs into it, and it relies on nftables set timeouts to
expire bans.
This project is still a proof of concept. It is useful for experiments and for people comfortable reading the code, but it is not packaged as a polished daemon yet.
RegBan starts one or more configured commands, usually something like
journalctl -f or tail -F. Each line is matched against the configured
regular expressions. Patterns use {{ip}} as the capture point for the source
address.
When a pattern matches, RegBan:
- Parses the IP address.
- Adds the pattern score to that address.
- Applies score decay over time.
- Looks up any extra score from configured IP range tables.
- Adds the IP to the configured
nftablesset when it reaches a ban threshold.
IPv4 and IPv6 are both supported, as long as matching nftables sets are
configured.
RegBan uses CMake and depends on libmnl, libnftnl, and yaml-cpp. The
repository can build yaml-cpp internally by default.
cmake -S . -B build
cmake --build build --target regbanTo use the system yaml-cpp instead:
cmake -S . -B build -DINTERNAL_YAML_CPP=OFF
cmake --build build --target regbanTests are available through the custom test target:
cmake --build build --target testCreate the sets before starting RegBan. For an inet table named default, a
minimal setup looks like this:
sudo nft add table inet default
sudo nft add set inet default blacklistv4 '{ type ipv4_addr; flags timeout; }'
sudo nft add set inet default blacklistv6 '{ type ipv6_addr; flags timeout, interval; }'
sudo nft add rule inet default input ip saddr @blacklistv4 drop
sudo nft add rule inet default input ip6 saddr @blacklistv6 dropThe IPv6 set needs interval because RegBan stores IPv6 bans as small ranges.
Start from examples/settings.yml. A typical SSH setup looks like this:
log:
level: info
cleanupinterval: 3600
nft:
table: default
type: inet
ipv4set: blacklistv4
ipv6set: blacklistv6
processes:
- name: sshd
command: "journalctl -t sshd -f -n 0 -q"
patterns:
- pattern: ".* Invalid user .* from {{ip}}.*"
score: 100
- pattern: ".* Failed password for .* from {{ip}} .*"
score: 50
- pattern: ".* Failed password for root from {{ip}} .*"
score: 200
rangetables: []
scores:
decay:
amount: 10
per: 3600
table:
100:
bantime: 86400
score: 0Score entries are keyed by the lower bound at which they apply. In the example
above, an address is banned for one day once its score reaches 100.
Set statefile if you want RegBan to persist current scores between restarts:
statefile: /var/lib/regban/state.ymlDry-run mode reads logs and prints what it would do without changing nftables:
./build/regban --dry-run examples/settings.ymlLive mode needs permission to talk to netfilter, so it usually runs as root:
sudo ./build/regban /etc/regban/settings.ymlYou can also pass configuration on stdin:
cat examples/settings.yml | ./build/regban -Range tables add or subtract score based on CIDR ranges. A range with a score of
0 or less acts as an allow-list entry for matching IPs.
CSV range tables use three columns:
192.0.2.0,24,50
fd00:11::,64,0IPv4 ranges must be at least /8. IPv6 ranges must be at least /18, because
the in-memory index uses the leading address bits.
- RegBan assumes log streaming is handled by another command.
- It depends on
nftablestimeouts for unbanning. - IPv6 handling stores and matches the first 64 bits internally.
- Configuration errors are generally fatal.
- There is no service unit, package, or install target yet.
The upside is that the moving parts are few: one process reads lines, scores matches, and writes directly to nftables.