Ir al contenido

Arquitectura

cs-routeros-bouncer actúa como puente entre la inteligencia de amenazas de CrowdSec y el firewall de MikroTik.

La LAPI de CrowdSec envía decisiones de ban y unban a cs-routeros-bouncer, que las aplica al router MikroTik a través de la API de RouterOS, expone métricas de Prometheus y sirve comprobaciones de salud. El router aplica los cambios a sus reglas de firewall y listas de direcciones.

El bouncer está compuesto por varios paquetes internos:

PaqueteResponsabilidad
cmd/cs-routeros-bouncerPunto de entrada de la CLI, enrutamiento de subcomandos
internal/configCarga de configuración, validación, vinculación de variables de entorno
internal/crowdsecCliente de streaming de la LAPI de CrowdSec
internal/routerosCliente de la API de RouterOS (direcciones, reglas de firewall)
internal/managerOrquestador central: conecta todas las piezas
internal/metricsMétricas de Prometheus y endpoint de salud
Al arrancar, el bouncer se conecta a CrowdSec y a MikroTik, crea las reglas de firewall, obtiene las decisiones activas y reconcilia las listas de direcciones. Durante el bucle de ejecución añade o elimina IPs a medida que CrowdSec informa de decisiones nuevas o expiradas, consultando primero su caché de direcciones. En un intervalo fijo vuelve a reconciliar para reparar la deriva. Al apagarse (SIGTERM) elimina sus reglas de firewall mientras las entradas de las address-lists expiran por su propio timeout.

Todos los recursos creados por el bouncer en MikroTik se etiquetan con un comentario estructurado:

{comment_prefix}:{type}-{chain}-{direction}-{protocol} @cs-routeros-bouncer

Ejemplos:

  • crowdsec-bouncer:filter-input-input-v4 @cs-routeros-bouncer
  • crowdsec-bouncer:raw-prerouting-input-v6 @cs-routeros-bouncer

Esto permite al bouncer identificar y gestionar con precisión sus propios recursos sin afectar a las reglas creadas por el usuario.

Al procesar una decisión de ban, el bouncer consulta primero su caché de direcciones en memoria:

  1. Si la dirección ya está en la caché, la llamada a la API de RouterOS se omite por completo.
  2. Si la dirección no está en la caché, intenta añadirla directamente (~1–3 ms).
  3. Si RouterOS devuelve already have such entry, lo trata como un conflicto a nivel de dispositivo, mantiene la conexión abierta, localiza la entrada existente y actualiza su timeout/comentario.

Esto es significativamente más rápido que el enfoque de “comprobar primero” (~400 ms por IP), que exigiría listar antes todas las entradas.

El bouncer mantiene un pool configurable de conexiones persistentes a la API de RouterOS. Durante la reconciliación, el trabajo se distribuye por el pool mediante el helper genérico ParallelExec; en un RB5009 con pool_size: 10, el trabajo completo de adición masiva en RouterOS para ~28.700 entradas de origen CAPI se completó en ~35–36 s.

Para la reconciliación inicial, el bouncer genera scripts de RouterOS que añaden entradas en bloques de 100 IPs por script. Cada entrada usa :do { ... } on-error={} para omitir los duplicados de forma controlada. Este enfoque es ~97× más rápido que las llamadas individuales secuenciales a la API para listas grandes — medido en un RB5009UG+S+ (RouterOS 7.22.1) con ~28.700 entradas de CAPI; consulta Benchmarking para la metodología.

Un mapa en memoria (map[string]struct{} con sync.RWMutex) registra todas las direcciones presentes actualmente en el router. Esto proporciona:

  • Búsquedas de unban en O(1): cuando se levanta el ban de una IP, primero se consulta la caché. Si la IP no está en la caché (por ejemplo, ya expiró en el router), la llamada a la API se omite por completo.
  • Ruta rápida en O(1) para bans duplicados: los eventos de ban repetidos para direcciones que ya se sabe que están en el router se resuelven de inmediato sin generar tráfico innecesario de gestión/API en RouterOS.
  • Prefiltrado durante el arranque: las eliminaciones recibidas durante la recogida inicial de decisiones se prefiltran contra los bans entrantes para evitar trabajo innecesario.

A diferencia de algunos bouncers que crean listas con marca de tiempo, cs-routeros-bouncer usa una única address-list con nombre por protocolo:

  • crowdsec-banned para IPv4
  • crowdsec6-banned para IPv6

Las reglas de firewall referencian estas listas por nombre, lo que es más eficiente y evita el problema de la duplicación.

Al arrancar, y después periódicamente según crowdsec.reconciliation_interval, el bouncer calcula la diferencia entre las decisiones activas de CrowdSec y el estado actual de la address-list de MikroTik:

  1. Obtener todas las decisiones activas de CrowdSec
  2. Obtener todas las entradas de la address-list de MikroTik
  3. Comparar ambos conjuntos
  4. Añadir las entradas que faltan (están en CrowdSec pero no en MikroTik)
  5. Eliminar las entradas obsoletas (están en MikroTik pero no en CrowdSec)

Esto mantiene la pertenencia sincronizada con independencia de cómo se detuvo el bouncer, de lo que ocurriera mientras estaba fuera de línea o de si las entradas del lado de RouterOS expiraron mientras CrowdSec aún las consideraba activas.