# KonfigurationJede Stellschraube, die der Daemon bietet — Umgebungsvariablen, Dateipfade und Integrationspunkte.

Der Daemon wird vollständig über Umgebungsvariablen und zwei
On-Disk-Dateien konfiguriert. Keine Code-Änderung nötig, um das
Verhalten zu justieren.

## Umgebungsvariablen

| Variable | Typ | Default | Zweck |
|---|---|---|---|
| `ABUSIVE_FAMILY` | `v4` / `v6` / `any` | `any` | Matching auf eine IP-Familie beschränken. |
| `ABUSIVE_MIN_HITS` | Integer ≥ 1 | `3` | Hits von einer Quelle, bevor die IP in die Blocklist geschrieben wird. |
| `ABUSIVE_SCOPE` | Komma-Liste | `request,ua` | Welche Log-Felder ausgewertet werden. Gültig: `request`, `ua`, `referrer`. |
| `ABUSIVE_REFERRER_DOMAINS` | Whitespace/Komma-Liste | _(leer)_ | Erlaubte Referrer-Hosts. Nur relevant, wenn `referrer` in `ABUSIVE_SCOPE`. |
| `ABUSIVE_SYSLOG_TAG` | String | `abusive_http_watch` | Syslog-Program-Tag. |
| `ABUSIVE_SYSLOG_FACILITY` | String | `daemon` | Syslog-Facility. `local0`–`local7` für eigene Routings. |
| `ABUSIVE_SYSLOG_PRIO` | `info` / `notice` / `warn` / `err` | `notice` | Syslog-Priorität für `added`-Events. |
| `ABUSIVE_DEBUG` | `0` / `1` | `0` | Verbose-stderr-Trace jeder Zeile. Nur für Scoping sinnvoll. |

### Anmerkungen

- **`ABUSIVE_MIN_HITS`** — Auf `1` setzen blockt beim ersten Hit.
  Aggressiver, aber erhöht das False-Positive-Risiko durch
  One-Shot-Probes von benign Cloud-IPs, die später regulär
  aufschlagen. Default `3` ist ein guter Kompromiss.
- **`ABUSIVE_SCOPE`** — `referrer` ist per Default aus, weil ein
  bösartiger Referrer per Drive-by die IP eines deiner Besucher in
  die Blocklist befördern könnte. Nur aktivieren, wenn auch
  `ABUSIVE_REFERRER_DOMAINS` als strikte Allowlist gesetzt ist.
- **`ABUSIVE_FAMILY`** — Nützlich, wenn man den Daemon über zwei
  Prozesse spiegeln will: einer für IPv4, einer für IPv6, jeder mit
  eigener Blocklist-Datei.

## Token-Set

Das Erkennungs-Regex-Set ist im Skript fest verdrahtet (`@TOKENS`)
und deckt acht Angriffsklassen ab — PHP-Exploitation,
WordPress-Probes, Path-Traversal, sensible Pfade, RCE/CGI-Versuche,
SQL-Injection, Login-Loop-Probes und Null-Byte-Injection.

Zum Anpassen des Sets:

1. Skript öffnen.
2. Das `@TOKENS`-Array justieren — Patterns hinzufügen oder
   entfernen, falls False Positives auftreten.
3. Daemon neu starten.

Das Set ist absichtlich konservativ. Tokens wie `/admin`, `/login`
oder `phpmyadmin` ohne Scoping hinzuzufügen führt zu False
Positives auf legitimen Traffic.

## Whitelist-Datei

Pfad: `/etc/abusive_http_whitelist`

Ein Eintrag pro Zeile. Drei Formate werden unterstützt:

```
# Kommentare erlaubt
203.0.113.42                    # einzelne IPv4
2001:db8::abcd                  # einzelne IPv6 (voll oder verkürzt)
203.0.113.0/24                  # IPv4 CIDR
2001:db8::/32                   # IPv6 CIDR
```

Whitelisted-IPs werden vollständig übersprungen — sie erhöhen
keinen Hit-Counter und landen nie in der Blocklist, selbst wenn
ihre Requests jedes Token im Set treffen.

Verwende die Whitelist für:

- Öffentliche Office- und VPN-IPs (Operatoren, die versehentlich
  Scanner auslösen).
- Such-Maschinen-Crawler-IP-Ranges, die dokumentiert legitim sind
  (Google, Bing). Vorher testen — selten nötig, weil deren Requests
  keine Angriffs-Token treffen.
- Monitoring-Dienste, die absichtlich `/wp-login.php` abfragen.

## Blocklist-Datei

Pfad: `/var/www/run/abusive_http_hosts`

Format: eine IP pro Zeile, keine Kommentare, keine Header, keine
Duplikate. Der Daemon stellt Deduplizierung über einen
In-Memory-Hash und `flock(LOCK_EX)` beim Schreiben sicher.

Die Datei ist zur Laufzeit **append-only** — alte Einträge werden
vom Daemon nie entfernt. Zum Aufräumen (z. B. Einträge nach 30
Tagen ablaufen lassen) externe Rotation verwenden:

```sh
# In einem Tages-Cron
mv /var/www/run/abusive_http_hosts /var/www/run/abusive_http_hosts.old
touch /var/www/run/abusive_http_hosts
chown _www:_www /var/www/run/abusive_http_hosts
doas rcctl restart abusive_http_watch
```

Das zwingt den Daemon, seinen In-Memory-State aus einer leeren
Datei neu aufzubauen. Die Firewall lädt die neue (leere) Blocklist
beim nächsten Cron-Tick.

## Firewall-Konsumption

Das Blocklist-Dateiformat ist absichtlich flach, damit jede
Schicht es konsumieren kann. Gängige Integrationen:

### OpenBSD `pf`

```pf
table <abusive> persist file "/var/www/run/abusive_http_hosts"
block in quick on egress from <abusive>
```

Tabelle neu laden:

```sh
pfctl -t abusive -T replace -f /var/www/run/abusive_http_hosts
```

### Linux `nftables`

```nft
table inet filter {
  set abusive_v4 {
    type ipv4_addr
    elements = { ... }
  }
  chain input {
    ip saddr @abusive_v4 drop
  }
}
```

Set per Helper aus Datei neu laden:

```sh
nft 'flush set inet filter abusive_v4'
awk '/^[0-9]/ {print}' /var/www/run/abusive_http_hosts | \
  xargs -I{} nft 'add element inet filter abusive_v4 { {} }'
```

### Apache

```apache
<RequireAll>
  Require all granted
  Require not ip 203.0.113.0/24
  # … ein Require not ip pro Blocklist-Eintrag
</RequireAll>
```

Per Templater (`m4`, `sed`) aus der Blocklist-Datei auf einem Cron
generiert. Reagiert langsamer als die Firewall-Integration,
funktioniert aber, wenn du die Firewall-Schicht nicht selbst
kontrollierst.

### nginx

```nginx
geo $abusive {
  default 0;
  include /var/www/run/abusive_http_nginx.conf;
}
server {
  if ($abusive) { return 444; }
}
```

`abusive_http_nginx.conf` wird per Template aus der Blocklist-Datei
generiert.
