No description
  • Go 82.5%
  • Shell 14.3%
  • Makefile 3.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
abrown38 9bb5155417 Release 0.1.0-rc.2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 01:32:20 +00:00
.gitea/workflows Release setup: tarballs, Gitea workflow, apt registry 2026-10-22 16:44:58 +01:00
cmd/guard Reload guard.yaml without losing the bounties 2026-10-25 01:32:20 +00:00
deploy Reload guard.yaml without losing the bounties 2026-10-25 01:32:20 +00:00
docs Reload guard.yaml without losing the bounties 2026-10-25 01:32:20 +00:00
internal Reload guard.yaml without losing the bounties 2026-10-25 01:32:20 +00:00
scripts CLI: shorter, plainer output 2026-10-23 12:53:37 +01:00
testdata/presets Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
.gitignore Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
AGENTS.md Release setup: tarballs, Gitea workflow, apt registry 2026-10-22 16:44:58 +01:00
CHANGELOG.md Reload guard.yaml without losing the bounties 2026-10-25 01:32:20 +00:00
CLAUDE.md Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
go.mod Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
go.sum Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
LICENSE Guard: watch logs, ban misbehaving addresses in Housecarl 2026-10-22 16:29:37 +01:00
Makefile Release setup: tarballs, Gitea workflow, apt registry 2026-10-22 16:44:58 +01:00
README.md Release 0.1.0-rc.2 2026-10-25 01:32:20 +00:00
VERSION Release 0.1.0-rc.2 2026-10-25 01:32:20 +00:00

Guard

Guard watches logs and bans the addresses that misbehave in them, at the firewall. It reads log files and the systemd journal, counts each address's bounty (its matches within a while), and once that reaches a watch's limit bans the address in a ban list of Housecarl, the firewall manager. The ban list says what a banned address is kept from: the firewall itself, some hosts behind it, or everything. Guard doesn't need to know anything about the firewall.

It is the fourth of a set with Jarl (BIND), Steward (DHCP) and Housecarl (nftables), and works like fail2ban, with one easy file instead of jails and filters spread over many:

housecarl:
  url: https://router.lan:8070
  token_file: /etc/guard/token
  list: web

watch:
  - name: ssh
    preset: sshd                     # OpenSSH, from the journal
    ban: {protocol: tcp, port: 22}
  - name: web-login
    file: /var/log/nginx/access.log
    match: ['^<IP> \S+ \S+ \[[^\]]+\] "POST /login[^"]*" 401 ']
    hits: 10
    ban: {time: 6h}
  • One pattern placeholder, <IP>. It matches IPv4 and IPv6 (bracketed, IPv4-mapped); what only looks like an address is never taken for one.
  • No date formats. Guard follows logs as they are written, and counts each line at the time it reads it (the journal's entries have their own time).
  • Files and the journal, the journal by unit or syslog identifier (sshd-session on Debian 13).
  • Presets for OpenSSH, Postfix, Dovecot, nginx, BIND zone transfers, Jarl, Housecarl and Steward, and Housecarl's own log of dropped packets, for scans (docs/presets.md).
  • Repeat offenders get longer bans: each earlier ban doubles the time, up to a week.
  • Never banned: your own addresses, from Guard's never_ban, and from Housecarl, which never bans the inside networks, the firewall's own addresses or the machine asking.
  • IPv6 by /64, as the ban list says: one customer usually has a whole /64 and moves around in it.
  • Housecarl away? Bans wait and are sent once it answers.
  • systemctl reload guard puts a changed guard.yaml to work without losing what Guard has counted.
  • guard test shows what a watch's patterns find in a log, and whom they would ban, before you trust it.

Documentation

Housecarl's side: its docs/bans.md.

Status

Guard 0.1.0 is in testing (0.1.0-rc.2). Go, CGO_ENABLED=0, Linux. MIT licence.