El daemon se configura íntegramente mediante variables de entorno y dos ficheros en disco. No se requiere ningún cambio de código para ajustar el comportamiento.

Variables de entorno

VariableTipoPor defectoPropósito
ABUSIVE_FAMILYv4 / v6 / anyanyRestringir matching a una familia de IP.
ABUSIVE_MIN_HITSentero ≥ 13Hits desde una fuente antes de escribir la IP a la blocklist.
ABUSIVE_SCOPElista comarequest,uaCampos del log a evaluar. Válidos: request, ua, referrer.
ABUSIVE_REFERRER_DOMAINSlista coma/espacio(vacío)Hosts referrer permitidos. Solo relevante si referrer está en ABUSIVE_SCOPE.
ABUSIVE_SYSLOG_TAGstringabusive_http_watchTag de programa syslog.
ABUSIVE_SYSLOG_FACILITYstringdaemonFacility de syslog. local0local7 para rutados personalizados.
ABUSIVE_SYSLOG_PRIOinfo / notice / warn / errnoticePrioridad syslog para eventos added.
ABUSIVE_DEBUG0 / 10Trace stderr verboso de cada línea. Útil solo durante scoping.

Notas

  • ABUSIVE_MIN_HITS — Ponerlo a 1 bloquea en el primer hit. Más agresivo, pero aumenta el riesgo de falsos positivos por probes one-shot que luego llegan desde una IP cloud benigna. El default 3 es un buen compromiso.
  • ABUSIVE_SCOPEreferrer está desactivado por defecto porque un referrer malicioso puede meter la IP de un visitante en la blocklist por drive-by. Solo activarlo si también se configura ABUSIVE_REFERRER_DOMAINS como allowlist estricta.
  • ABUSIVE_FAMILY — Útil si quieres correr dos daemons en paralelo: uno para IPv4, otro para IPv6, cada uno con su propia blocklist.

Conjunto de tokens

El conjunto de regex de detección está cableado en el script (@TOKENS) y cubre ocho clases de ataque — explotación PHP, probes WordPress, path traversal, rutas sensibles, intentos RCE/CGI, SQL-injection, probes de bucle de login, inyección null-byte.

Para ajustarlo:

  1. Abrir el script.
  2. Ajustar el array @TOKENS — añadir patrones, quitar los que disparen falsos positivos en tu entorno.
  3. Reiniciar el daemon.

El conjunto es deliberadamente conservador. Añadir tokens como /admin, /login o phpmyadmin sin scoping causará falsos positivos sobre tráfico legítimo.

Fichero whitelist

Ruta: /etc/abusive_http_whitelist

Una entrada por línea. Tres formatos soportados:

# Comentarios permitidos
203.0.113.42                    # IPv4 individual
2001:db8::abcd                  # IPv6 individual (completo o abreviado)
203.0.113.0/24                  # CIDR IPv4
2001:db8::/32                   # CIDR IPv6

Las IPs whitelisteadas se ignoran completamente — no incrementan contadores y nunca acaban en la blocklist, aunque sus peticiones toquen todos los tokens.

Usar la whitelist para:

  • IPs públicas de oficina y VPN (operadores disparando scanners por accidente).
  • Rangos de IPs de crawlers de buscadores documentados como legítimos (Google, Bing). Probar antes — rara vez necesario porque sus peticiones no tocan tokens de ataque.
  • Servicios de monitorización que sondean /wp-login.php a propósito.

Fichero blocklist

Ruta: /var/www/run/abusive_http_hosts

Formato: una IP por línea, sin comentarios, sin cabeceras, sin duplicados. El daemon garantiza dedup vía hash en memoria y flock(LOCK_EX) al escribir.

El fichero es append-only en runtime — el daemon nunca borra entradas antiguas. Para purgar (p. ej. caducar tras 30 días) usar rotación externa:

# En un cron diario
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

Esto fuerza al daemon a reconstruir su estado en memoria desde un fichero vacío. El firewall cargará la nueva blocklist (vacía) en el siguiente tick de cron.

Consumo por el firewall

El formato del fichero blocklist es intencionadamente plano para que cualquier capa pueda consumirlo. Integraciones comunes:

OpenBSD pf

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

Recarga de la tabla:

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

Linux nftables

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

Recarga del set vía helper:

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

<RequireAll>
  Require all granted
  Require not ip 203.0.113.0/24
  # … un Require not ip por entrada de blocklist
</RequireAll>

Generado por templater (m4, sed) desde el fichero blocklist en un cron. Reacciona más lento que la integración con el firewall, pero funciona cuando no se controla la capa firewall.

nginx

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

abusive_http_nginx.conf se genera por template desde el fichero blocklist.