# 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 `` once, where the address is: ```yaml match: - '^ \S+ \S+ \[[^\]]+\] "POST /login[^"]*" 401 ' - 'authentication failure; .* rhost=(?: |$)' ``` `` 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 `` 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.