Files
guard/docs/presets.md
T
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

86 lines
3.7 KiB
Markdown

# Presets and patterns
A preset is a watch Guard knows: its patterns, and where its program's
lines usually are. `guard presets` lists them; `guard presets sshd`
shows one's patterns.
```yaml
watch:
- name: ssh
preset: sshd
ban: {protocol: tcp, port: 22}
- name: ssh-file # the same, from a syslog file
preset: sshd
file: /var/log/auth.log
```
A watch's own `file` or `journal` replaces the preset's source, and its
`match` and `ignore` lines are added to the preset's.
| Preset | Source | Matches |
|---|---|---|
| `sshd` | journal, identifiers `sshd`, `sshd-session` | failed passwords and keys, unknown users, connections closed before login, too many attempts, failed key exchanges, garbage banners |
| `jarl`, `housecarl`, `steward` | journal, units `jarl.service`, `housecarl.service`, `steward.service` | their failed logins and refused API tokens (`msg="login failed" ip=…`, text or JSON logs) |
| `bind-xfr` | journal, identifier `named` | zone transfers BIND refused (TCP, so the address is real) |
| `postfix-sasl` | journal, identifiers `postfix/smtpd`, `postfix/submission/smtpd`, `postfix/smtps/smtpd` | failed SMTP logins |
| `dovecot` | journal, identifier `dovecot` | failed IMAP, POP3, submission and ManageSieve logins |
| `nginx-auth` | file `/var/log/nginx/error.log` | failed HTTP basic authentication |
| `housecarl-drops` | Housecarl's log of dropped packets | every TCP packet a logged rule dropped (on the firewall, for scans) |
OpenSSH 9.8 and later (Debian 13) logs logins from `sshd-session`, not
`sshd`; the preset reads both. Debian 13 has no `/var/log/auth.log`
unless rsyslog is installed: the journal is the place.
There's deliberately no preset for BIND's refused queries: they come
over UDP, whose source address anyone can fake, so banning on them would
let a stranger get your users' resolvers banned. Use BIND's response
rate limiting for floods.
## Writing patterns
A pattern is a Go regular expression ([RE2 syntax](https://github.com/google/re2/wiki/Syntax))
with `<IP>` once, where the address is:
```yaml
match:
- '^<IP> \S+ \S+ \[[^\]]+\] "POST /login[^"]*" 401 '
- 'authentication failure; .* rhost=<IP>(?: |$)'
```
`<IP>` matches IPv4 and IPv6 addresses, bracketed (`[2001:db8::9]`),
IPv4-mapped (`::ffff:203.0.113.9`, counted as `203.0.113.9`) or with a
zone. The text it matches must be a real address: `12:34:56` isn't one.
Patterns match anywhere in a line unless anchored. A line from a syslog
file starts with its date, host and program (`Oct 22 10:00:01 web
sshd[123]: `); a journal entry is the message alone. The presets begin
with `(?:^|: )` so they work on both.
**Where the address is matters.** Many log lines carry text a client
chose: a user name, a URL, a reverse DNS name. If a pattern lets that
text supply the address, a client can get any address banned:
```
Failed password for invalid user x from 198.51.100.1 port 22 from 203.0.113.9 port 4444 ssh2
```
Anchor patterns at the end of the line, or put `<IP>` where the
program writes the address after the client's text, so it is the
program's address that matches. The presets do; `guard test` shows
what yours find. Programs that log the address first (Jarl, Housecarl,
Steward log `msg="login failed" ip=… user=…`) are the easiest to match
safely.
## Trying patterns: guard test
```sh
guard test web-login /var/log/nginx/access.log.1
guard test ssh # a journal watch: its last 5000 entries
zcat /var/log/nginx/access.log.2.gz | guard test web-login -
```
It prints each matching line with its address, then the addresses that
would be banned. Nothing is banned. Lines from a file carry no time
Guard reads, so every match counts however far apart; the journal's
entries have times, and the watch's window is used.