Files
abrown38andClaude Opus 5.5 d06bf8d531 Guard: watch logs, ban misbehaving addresses in Housecarl
Files and the journal, patterns with one <IP>, bounties within a window,
bans in a Housecarl ban list with repeat offenders' bans growing; presets
for sshd, jarl, housecarl, steward, bind-xfr, postfix-sasl, dovecot,
nginx-auth and housecarl-drops; guard run/check/test/status/bans/ban/unban;
a Debian package with a sandboxed unit; an end-to-end test with Housecarl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:29:37 +01:00

71 lines
3.1 KiB
YAML

# Guard's presets (docs/presets.md): patterns for common programs, and
# where their lines usually are. A watch's own file or journal replaces
# the preset's source; its match and ignore lines are added to these.
#
# Patterns are anchored where the program's format allows, and put the
# address where the program writes it, after anything a client chooses
# (a user name), so a chosen name can't plant another address. Lines
# from a syslog file carry a "host prog[pid]: " head that journal
# messages don't, hence "(?:^|: )" before a message's first word.
sshd:
description: OpenSSH's failed logins, unknown users and broken handshakes
# OpenSSH 9.8 and later (Debian 13) logs from sshd-session.
journal: {identifier: [sshd, sshd-session]}
match:
- '(?:^|: )Failed (?:password|publickey|keyboard-interactive/pam|none) for .* from <IP> port \d+(?: ssh2)?$'
- '(?:^|: )Invalid user .* from <IP> port \d+$'
- '(?:^|: )(?:Connection (?:closed|reset)|Disconnected) (?:by|from) (?:invalid|authenticating) user .* <IP> port \d+ \[preauth\]$'
- '(?:^|: )error: maximum authentication attempts exceeded for .* from <IP> port \d+ ssh2 \[preauth\]$'
- '(?:^|: )Unable to negotiate with <IP> port \d+: no matching (?:key exchange method|host key type|cipher|MAC) found'
- '(?:^|: )banner exchange: Connection from <IP> port \d+: invalid format$'
jarl:
description: failed logins and refused API tokens of Jarl (the BIND manager)
journal: {unit: jarl.service}
match:
- 'msg="(?:login failed|token refused)" ip=<IP> '
- '"msg":"(?:login failed|token refused)","ip":"<IP>"'
housecarl:
description: failed logins and refused API tokens of Housecarl (the firewall manager)
journal: {unit: housecarl.service}
match:
- 'msg="(?:login failed|token refused)" ip=<IP> '
- '"msg":"(?:login failed|token refused)","ip":"<IP>"'
steward:
description: failed logins and refused API tokens of Steward (the DHCP server)
journal: {unit: steward.service}
match:
- 'msg="(?:login failed|token refused)" ip=<IP> '
- '"msg":"(?:login failed|token refused)","ip":"<IP>"'
bind-xfr:
description: zone transfers BIND refused (over TCP, so the address is real)
journal: {identifier: named}
match:
- 'client @0x[0-9a-f]+ <IP>#\d+ .*: zone transfer .* denied$'
postfix-sasl:
description: Postfix's failed SMTP logins (SASL)
journal: {identifier: [postfix/smtpd, postfix/submission/smtpd, postfix/smtps/smtpd]}
match:
- 'warning: [-._0-9A-Za-z]+\[<IP>\]: SASL [-A-Z0-9]+ authentication failed'
dovecot:
description: Dovecot's failed IMAP and POP3 logins
journal: {identifier: dovecot}
match:
- '(?:imap|pop3|submission|managesieve)-login: (?:Disconnected|Aborted login).*\(auth failed, \d+ attempts? in \d+ secs\): user=<.*>, .*rip=<IP>, lip='
nginx-auth:
description: nginx's failed HTTP basic authentication (error.log)
file: /var/log/nginx/error.log
match:
- '\buser "[^"]*"(?: was not found in "[^"]*"|: password mismatch), client: <IP>, server: '
housecarl-drops:
description: packets Housecarl's rules dropped and logged (on the firewall; TCP only by default)
source: housecarl-drops