Rotation des logs

Le daemon gère les deux schémas standard de rotation :

  • Rotate-and-rename (le log est renommé, un nouveau fichier prend sa place). Détecté via changement d’inode/device sur le chemin surveillé.
  • Copytruncate (le contenu est copié ailleurs puis l’original est tronqué à zéro). Détecté via tell() > stat().

Dans les deux cas, le daemon réouvre le fichier au début et écrit info reopen after rotate dev=… ino=… (rotate-and-rename) ou info truncate file shrank (copytruncate) sur stderr.

Si vous observez des entrées manquantes autour de la rotation, vérifiez la configuration de l’outil de rotation :

  • Sur OpenBSD newsyslog, la rotation par défaut est rotate-and-rename — aucune configuration particulière requise.
  • Sur Linux logrotate, préférez le défaut (rotation puis SIGHUP au serveur web) au mode copytruncate. Les deux fonctionnent, mais rotate-and-rename est moins coûteux et ne perd aucune ligne.

Script rc.d (OpenBSD)

Variante minimale /etc/rc.d/abusive_http_watch :

#!/bin/ksh
daemon="/usr/local/sbin/abusive_http_watch"
daemon_flags="/var/www/logs/access.log"
daemon_user="_www"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_cmd $1

Puis :

doas rcctl enable abusive_http_watch
doas rcctl start abusive_http_watch
doas rcctl check abusive_http_watch

Sur Linux avec systemd, voir la documentation de la distribution ; une simple unité Type=simple pointant sur /usr/local/sbin/abusive_http_watch avec les mêmes arguments suffit.

Événements syslog

Le daemon émet une classe d’événements — added — lorsqu’une nouvelle IP franchit le seuil de hits. Format :

<syslog-tag>[<pid>]: added ip=<ip> path=<chemin-blocklist>

Exemple :

abusive_http_watch[12345]: added ip=198.51.100.42 path=/var/www/run/abusive_http_hosts

Router via syslog.conf vers un fichier dédié pour revue :

local0.notice                                          /var/log/abusive_http.log

Combiné avec ABUSIVE_SYSLOG_FACILITY=local0, cela donne un log d’audit propre de chaque IP bloquée.

Signaux de monitoring

Pour un monitoring automatisé, deux indicateurs utiles :

  • Taux de croissance de la blocklistwc -l /var/www/run/abusive_http_hosts dans le temps. Sur un serveur web public, cela devrait croître régulièrement (plusieurs IP par jour à beaucoup par heure, selon l’exposition). Une stagnation de 24h sur un site public suggère que le daemon ne tourne pas ou lit le mauvais log.
  • Santé du processuspgrep -f abusive_http_watch devrait toujours retourner une PID. Alerter si zéro.

Pour les systèmes avec Prometheus, un petit exporter qui se contente de wc -l le fichier blocklist et d’exposer la valeur comme gauge suffit. Aucun endpoint metrics dans le daemon lui-même — par conception, pour le garder sans dépendances.

Troubleshooting

Le fichier blocklist reste vide

Causes possibles, par ordre de probabilité :

  1. Le daemon lit le mauvais fichier. Lancer au premier plan avec ABUSIVE_DEBUG=1. Confirmer qu’il logge start following dev=… ino=… pour le chemin attendu. Sinon, corriger l’argument.
  2. Aucun trafic d’attaque réel. Improbable sur un serveur public, possible sur un interne. Lancer avec ABUSIVE_DEBUG=1 et chercher des lignes [dbg] ip=… sans [dbg] token match correspondant.
  3. La whitelist absorbe tout. Vérifier /etc/abusive_http_whitelist — une entrée CIDR /0 errante whiteliste tout l’internet. Retirer et redémarrer.
  4. Seuil de hits trop élevé. Baisser ABUSIVE_MIN_HITS à 1 temporairement et observer.

La blocklist croît mais le pare-feu ne bloque pas

Le daemon écrit le fichier. Il faut dire au pare-feu de le lire. Vérifier :

  • Cron recharge la table pf / le set nftables toutes les quelques minutes (le daemon n’appelle pas pfctl lui-même).
  • La règle pare-feu référençant la table est dans la bonne chaîne et assez quick pour prendre effet avant toute règle pass ultérieure.

Des utilisateurs légitimes sont bloqués

Ajouter leur IP publique ou plage CIDR à /etc/abusive_http_whitelist. Le daemon relit la whitelist à chaque ligne — les changements prennent effet en quelques secondes.

Pour retirer une seule IP de la blocklist existante, éditer le fichier directement et recharger la table pare-feu. Le daemon n’a pas besoin de redémarrer — il ne réajoutera l’IP que si l’utilisateur retouche des tokens.

Le daemon crashe après une rotation de log

Ne devrait pas arriver vu la gestion de rotation décrite plus haut. Si c’est le cas, lancer au premier plan avec ABUSIVE_DEBUG=1, déclencher une rotation, capturer stderr. Envoyer le log capturé via la page Contact — c’est un vrai bug à corriger.

Arrêt propre

Le daemon attrape SIGTERM et sort proprement après l’itération courante :

doas rcctl stop abusive_http_watch

Logge [info] TERM received, exiting, ferme le handle de logfile, flushe toute écriture pendante, et sort avec status 0. Aucune corruption d’état, même sur un log très actif.