Operación
Rotación de logs
El daemon maneja los dos esquemas estándar de rotación:
- Rotate-and-rename (el log se renombra, un nuevo fichero toma su lugar). Detectado por cambio de inodo/device en la ruta vigilada.
- Copytruncate (el contenido se copia a otro sitio y luego se
trunca el original a cero). Detectado por
tell() > stat().
En ambos casos el daemon reabre el fichero desde el principio y
escribe info reopen after rotate dev=… ino=… (rotate-and-rename)
o info truncate file shrank (copytruncate) en stderr.
Si observas entradas perdidas alrededor de la rotación, revisa la config de la herramienta de rotación:
- En OpenBSD
newsyslog, la rotación por defecto es rotate-and-rename — no requiere configuración especial. - En Linux
logrotate, preferir el default (rotar y SIGHUP al servidor web) sobre el modocopytruncate. Ambos funcionan, pero rotate-and-rename es más barato y no pierde líneas.
Script rc.d (OpenBSD)
Variante mínima /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 $1Luego:
doas rcctl enable abusive_http_watch
doas rcctl start abusive_http_watch
doas rcctl check abusive_http_watchEn Linux con systemd, ver la doc de la distribución; una unidad
simple Type=simple apuntando a
/usr/local/sbin/abusive_http_watch con los mismos argumentos
basta.
Eventos syslog
El daemon emite una clase de evento — added — cuando una IP
cruza el umbral de hits. Formato:
<syslog-tag>[<pid>]: added ip=<ip> path=<ruta-blocklist>Ejemplo:
abusive_http_watch[12345]: added ip=198.51.100.42 path=/var/www/run/abusive_http_hostsRutar vía syslog.conf a un fichero dedicado para revisión:
local0.notice /var/log/abusive_http.logCombinado con ABUSIVE_SYSLOG_FACILITY=local0, da un log de
auditoría limpio de cada IP bloqueada.
Señales de monitorización
Para monitorización automatizada, dos indicadores útiles:
- Tasa de crecimiento de la blocklist —
wc -l /var/www/run/abusive_http_hostsen el tiempo. En un servidor web público debería crecer de forma sostenida (varias IPs por día a muchas por hora, según exposición). Una línea plana de 24h en un sitio público sugiere que el daemon no corre o lee el log equivocado. - Salud del proceso —
pgrep -f abusive_http_watchdebería retornar siempre un PID. Alertar si cero.
Para sistemas con Prometheus, un exporter pequeño que solo
wc -l el fichero blocklist y exponga el conteo como gauge es
suficiente. No hay endpoint de métricas dentro del daemon — por
diseño, para mantenerlo sin dependencias.
Troubleshooting
El fichero blocklist se queda vacío
Causas posibles, por orden de probabilidad:
- El daemon lee el fichero equivocado. Lanzar en primer
plano con
ABUSIVE_DEBUG=1. Confirmar que logeastart following dev=… ino=…para la ruta esperada. Si no, corregir el argumento. - No hay tráfico de ataque real. Improbable en un servidor
web público, posible en uno interno. Lanzar con
ABUSIVE_DEBUG=1y buscar líneas[dbg] ip=…sin[dbg] token matchasociado. - La whitelist se traga todo. Revisar
/etc/abusive_http_whitelist— una entrada CIDR/0errante whitelistea internet entero. Quitar y reiniciar. - Umbral de hits demasiado alto. Bajar
ABUSIVE_MIN_HITSa1temporalmente y observar.
La blocklist crece pero el firewall no bloquea
El daemon escribe el fichero. Hay que decirle al firewall que lo lea. Verificar:
- Cron recarga la tabla
pf/ el setnftablescada pocos minutos (el daemon no llama apfctlpor sí mismo). - La regla firewall que referencia la tabla está en la cadena
correcta y suficientemente
quickpara tomar efecto antes de cualquierpassposterior.
Usuarios legítimos están siendo bloqueados
Añadir su IP pública o rango CIDR a
/etc/abusive_http_whitelist. El daemon relee la whitelist en
cada línea — los cambios surten efecto en segundos.
Para retirar una IP individual de la blocklist existente, editar el fichero directamente y recargar la tabla firewall. El daemon no necesita reinicio — no la añadirá de nuevo a menos que el usuario vuelva a tocar tokens.
El daemon crashea tras una rotación de logs
No debería ocurrir dado el manejo de rotación descrito arriba.
Si ocurre, lanzar en primer plano con ABUSIVE_DEBUG=1,
provocar una rotación, capturar stderr. Enviar el log capturado
por la página de
Contacto — eso es un bug real
que merece arreglarse.
Apagado limpio
El daemon captura SIGTERM y sale limpiamente tras la iteración
actual:
doas rcctl stop abusive_http_watchLogea [info] TERM received, exiting, cierra el handle del log,
flushea cualquier escritura pendiente y sale con status 0. Sin
corrupción de estado, ni siquiera en un log muy activo.