Ir al contenido

Reconciliación

Cómo mantiene el bouncer la pertenencia a las address-lists de MikroTik sincronizada con las decisiones de CrowdSec.

Cuando el bouncer arranca (o se reinicia), o durante el intervalo de reconciliación periódica, la address-list de MikroTik puede estar desincronizada con las decisiones activas de CrowdSec:

  • Puede que se hayan añadido IPs a CrowdSec mientras el bouncer estaba fuera de línea
  • Puede que haya IPs que expiraron en CrowdSec pero sigan en la lista de MikroTik
  • Puede que haya IPs que expiraron o se eliminaron manualmente en MikroTik mientras seguían activas en CrowdSec
  • Pueden seguir existiendo entradas del bouncer de una ejecución anterior

Por defecto, la reconciliación se ejecuta al arrancar y después cada 15m. Configura crowdsec.reconciliation_interval para cambiar esta cadencia. Establécelo a 0 para desactivar la reconciliación periódica; los valores por debajo de 1m se rechazan al arrancar, así que usa 0 para desactivarla o una duración de 1m o superior para activarla.

  1. Recopilar

    Obtener todas las decisiones activas de CrowdSec y todas las entradas de la address-list de MikroTik.

  2. Comparar

    Comparar ambos conjuntos para determinar qué IPs hay que añadir y cuáles eliminar.

  3. Refrescar la caché

    Sustituir la caché de direcciones en memoria de esta familia por lo que el router acaba de comunicar, antes de que salga una sola adición o eliminación, para que los manejadores de ban y unban en vivo dejen de fiarse de entradas que el router ya no tiene.

  4. Aplicar

    Ejecutar las adiciones (mediante scripts masivos, 100 IPs por lote) y las eliminaciones (llamadas paralelas a la API a través del pool de conexiones cuando este llegó a abrirse, y una a una por la conexión principal cuando no). Cada una de las dos actualiza la caché con lo que ha intentado escribir.

  5. Verificar

    Registrar las métricas de reconciliación y los recuentos finales para confirmar que la pertenencia a la address-list coincide con CrowdSec.

La comparación se hace por familia de protocolo y por address-list. Entran dos conjuntos —lo que CrowdSec dice que debe estar bloqueado y lo que el router tiene ahora mismo— y salen dos listas.

Una instantánea de decisiones activas se convierte en el conjunto deseado, una entrada por decisión de esta familia de protocolo, indexada por dirección normalizada. La address-list del router se convierte en el conjunto presente, pero solo con las entradas cuyo comentario empieza por el prefijo configurado; las entradas con cualquier otro comentario se traen del router y se descartan en el cliente, así que no se comparan ni se eliminan, pero sí cuestan transferencia en cada pasada. Comparar ambos conjuntos dirección a dirección da las entradas que hay que añadir y las que hay que eliminar. La caché de direcciones en memoria se sustituye a partir de ese mismo listado antes de que salga ninguna escritura. Las adiciones pasan después por un script de RouterOS de hasta cien entradas, y si un script falla se recurre a una llamada a la API por entrada; las eliminaciones pasan por el pool de conexiones cuando se pudo abrir, y una a una por la conexión principal cuando no. Cada adición y cada eliminación vuelve a actualizar la caché con lo que ha escrito, y las métricas de reconciliación se registran cuando ya han corrido las dos.

El filtro por prefijo sobre el conjunto presente es lo que hace seguro apuntar la reconciliación a una lista compartida. El bouncer pide a RouterOS la lista por su nombre y después se queda solo con las entradas cuyo comentario empieza por el comment_prefix configurado, así que una dirección que añadiste a mano —o que mantiene otra herramienta— ni siquiera entra en la comparación, y la rama de «presente y no deseada» no puede alcanzarla.

La comparación es por dirección normalizada, no por decisión: varias decisiones sobre la misma IP se colapsan en una sola entrada deseada, y solo la última leída aporta el timeout y el comentario con los que se escribe.

Medido en un MikroTik RB5009UG+S+ (ARM64, 4 núcleos @ 1400 MHz, 1 GB de RAM, RouterOS 7.22.1) con mikrotik.pool_size: 10:

MétricaCAPI completo (~28.700 IPs)
Reconciliación en frío (tiempo total)~58 s
Trabajo de adición masiva en RouterOS~35–36 s
Pico de CPU observado en el router~39% durante grandes ráfagas de adición/eliminación
Comprobación periódica sin deriva~3–4 s, sin escrituras de adición/eliminación
Eliminación masiva CAPI → solo local~26.800 eliminaciones en ~77 s de trabajo de eliminación en RouterOS

La fila de comprobación sin deriva de arriba pertenece a la versión y a la lista con la que se midió. Dos cambios posteriores la movieron: la pasada de reconciliación dejó de pedir dos propiedades de la address-list que no lee nadie (−11,2%), y un desbaneo individual dejó de recorrer la lista para redescubrir un id que ya tenía. Vuelta a medir en el mismo equipo con RouterOS 7.24.1, guardando 22.857 entradas (22.332 IPv4 más ~525 IPv6) con intervalo de 60 s, y tomada del propio histograma operation_duration_seconds del bouncer en lugar de con un cronómetro:

Métrica22.857 entradas, RouterOS 7.24.1
Comprobación periódica sin deriva1,86 s a lo largo de 28 ciclos seguidos
Ciclo de trabajo con intervalo de 60 s3,1% del tiempo real
Parte gastada en las dos lecturas98,5%

Qué implica esto para el ajuste: el coste lo domina la lectura de la lista, así que escala con cuántas entradas guarda el router, no con cuánta deriva haya que reparar. Una pasada que no encuentra nada que arreglar cuesta prácticamente lo mismo que una que sí. Además hay un suelo que ninguna reducción de propiedades alcanza — un listado count-only de la misma lista sigue costando 1,18 s — así que preguntarle al router “¿ha cambiado algo?” no sale apreciablemente más barato que pedirle todo.

La reconciliación periódica suele ser ligera: cuando no hay deriva, lista las entradas actuales de la address-list, las compara con el snapshot activo de CrowdSec, actualiza los contadores y no realiza escrituras de adición/eliminación.

En lugar de llamadas individuales a la API (~97× más lentas), el bouncer sube un script temporal de RouterOS llamado crowdsec-bulk-import y lo ejecuta por su id interno:

/system/script/run =number=<script-id>

Cada ejecución del script añade hasta 100 IPs usando :do { ... } on-error={} para gestionar los duplicados de forma controlada.

Las eliminaciones usan el pool de conexiones configurado con llamadas concurrentes a la API. En la prueba de CAPI con el RB5009, eliminar ~26.800 entradas exclusivas de CAPI llevó ~77 s de trabajo de eliminación en RouterOS.

Durante la recogida inicial de decisiones, si se reciben un ban y su unban correspondiente para la misma IP, el unban prefiltra el ban y lo elimina del conjunto pendiente. Esto evita añadir y eliminar inmediatamente la misma IP.