Anatomía de un sistema de detección de intrusiones de red
Disección de protocolos por capas, reglas inspiradas en Snort y detección con estado; análisis de 500K+ paquetes/s en un solo hilo con SYN sintéticos.
La canalización de IDS
Los sistemas comerciales de detección de intrusiones, como Snort y Suricata, siguen una arquitectura común: Capturar → Analizar → Detectar → Alertar. SentinelFlow implementa el recorrido completo en C++17 con libpcap y analiza 500K+ paquetes/s en un solo hilo.
Captura: los filtros BPF se ejecutan en el núcleo
SentinelFlow utiliza libpcap con la interfaz polimórfica PacketCapture: LiveCapture para tráfico en tiempo real y PcapFileReader para análisis sin conexión. La optimización decisiva es BPF: una expresión como tcp port 80 se compila mediante pcap_compile() y se ejecuta dentro del núcleo. Los paquetes que no coinciden nunca se copian al espacio de usuario, lo que resulta mucho más eficiente que filtrar en el código de la aplicación.
Disección de protocolos por capas
Las tramas de red son estructuras anidadas. No se puede saltar a un desplazamiento de bytes fijo porque cada capa puede variar de longitud:
- Ethernet (14 bytes),
ntohssobre EtherType dirige a IPv4 (0x0800) o ARP (0x0806) - IPv4: IHL indica dónde comienza L4; la longitud varía por las opciones de IP.
- TCP:
data_offsetindica dónde empieza la carga útil; la longitud varía por las opciones de TCP. - UDP (8 bytes), cabecera fija, pero activa el análisis DNS si el puerto es 53
- DNS: recorre nombres de consulta codificados en etiquetas, con segmentos precedidos de su longitud
- ICMP / ARP, códigos de tipo y direcciones de hardware
Cada analizador es una función independiente sin estado que opera sobre const uint8_t* sin procesar, sin copias ni asignaciones. ParsedPacket usa std::optional<T> para cada capa: si falla el análisis o no existe el protocolo, queda vacío y se omiten las capas posteriores.
Motor de reglas inspirado en Snort
SentinelFlow implementa un subconjunto del lenguaje de reglas de Snort, estándar habitual de la detección por firmas:
alert tcp any any -> any 22 (msg:"SSH brute force"; flags:S; threshold:10,60; sid:2001;)Las reglas son declarativas. La cabecera es un prefiltro rápido para protocolo, IP y puerto; las opciones afinan la coincidencia: máscaras de bits, cadenas de contenido y umbrales de longitud de consultas DNS. El analizador extrae estos elementos en objetos estructurados que el comparador de firmas evalúa para cada paquete.
Detección con estado y sin estado
Las firmas detectan patrones maliciosos conocidos en paquetes individuales. Sin embargo, muchos ataques reales se distribuyen entre varios paquetes:
- Escaneos de puertos: solo se detectan al seguir el conjunto de puertos destino por IP origen en el tiempo. SentinelFlow mantiene un
std::set<uint16_t>por par de IP y alerta cuando se alcanzan 15+ puertos únicos en 60 segundos. - Inundaciones SYN: se detectan mediante la tasa de conexiones semiabiertas. Un
std::dequeguarda marcas SYN por IP destino y elimina entradas antiguas al acceder. Alerta ante 100+ SYN en 10 segundos. - Túneles DNS: la exfiltración por consultas codificadas genera nombres anormalmente largos. El detector sigue consultas de más de 50 caracteres y alerta cuando su volumen supera el umbral.
Todos los detectores con estado usan ventanas temporales deslizantes con limpieza diferida: las entradas antiguas se eliminan en el siguiente acceso, no mediante un hilo en segundo plano. Así se evita la sobrecarga de sincronización.
Rendimiento del análisis sin copias
Los analizadores operan directamente sobre el búfer de libpcap, sin copias intermedias ni asignación dinámica por paquete. El patrón memcpy + ntohs/ntohl es habitual en el procesamiento de alto rendimiento, como DPDK, PF_RING y NIDS en producción. El benchmark demuestra 500K+ paquetes/s en un hilo: mide únicamente el análisis de paquetes TCP SYN sintéticos.
Salidas de alerta
El sistema de alertas usa el patrón estrategia; AlertManager envía cada alerta a todas las salidas registradas:
- Consola: colores ANSI según gravedad (verde → amarillo → rojo → rojo en negrita)
- CSV: conforme a RFC 4180, con escape correcto y listo para incorporación al SIEM
Añadir una salida como syslog, webhook o Kafka solo exige implementar un método emit().