Dialogo con Gemini.
Ho usato in modo esteso network sniffer opensource su Linux o Bastioni di sicurezza, in particolare UTM. Potresti fare il punto attuale?
Il panorama dell’analisi del traffico e delle appliance perimetrali open source è cambiato radicalmente negli ultimi anni. Due forze principali hanno guidato questa evoluzione: l’onnipresenza della cifratura (TLS 1.3, DoH, QUIC/HTTP3), che ha reso obsoleta la sola ispezione del payload in chiaro, e la migrazione verso paradigmi come il Zero Trust e l’architettura a microservizi/container.
1. Bastioni e UTM Open Source (NGFW)
Il concetto tradizionale di UTM monolitico “tuttofare” (routing + proxy Squid + ClamAV + firewall) ha lasciato il passo ai Next-Generation Firewall (NGFW) modulari, dove i proxy HTTP tradizionali sono quasi scomparsi a favore di motori DPI layer-7 e filtraggio basato su reputazione DNS/SNI.
- OPNsense (HardenedBSD/FreeBSD): È diventato il punto di riferimento primario per innovazione open source. Architettura pulita con framework MVC e API REST native, aggiornamenti bi-settimanali puntuali e integrazione di motori moderni: Regulus
- Zenarmor (ex Sensei): plugin di punta che trasforma OPNsense in un vero NGFW Layer 7 con classificazione applicativa e controlli granulari (senza necessitare di proxy intermedi).
- Suricata integrato: sfruttato in modalità inline (Netmap) per IPS ad alte prestazioni. AIMultiple
- pfSense (CE vs Plus): La versione open source pura (Community Edition) è stata progressivamente messa in secondo piano da Netgate a favore di pfSense Plus (closed-source/commerciale). Resta estremamente stabile ed esteso negli ambienti legacy, ma la community indipendente è migrata in gran parte verso OPNsense.
- IPFire (Linux-based): Basato su kernel Linux puro e stack Netfilter/nftables. Molto focalizzato sulla sicurezza minimalista e sulla resilienza, impiega Suricata come motore IPS predefinito. Ideale quando si cerca un’impronta Linux nativa leggera anziché un sistema BSD.
- Distribuzioni storiche (IPCop, Endian, Smoothwall, Untangle):
- IPCop e Smoothwall GPL: sostanzialmente abbandonati da anni o fermi a vecchi rami storici.
- Untangle (NG Firewall): acquisito da Arista Networks, ha chiuso i canali gratuiti/community diventando una soluzione proprietaria enterprise a pagamento. AIMultiple
- Endian: mantiene una Community Edition, ma l’innovazione principale si è spostata sulla gamma commerciale IoT/industrial. AIMultiple
2. Sniffing e Network Security Monitoring (NSM) BestDefense
La cattura pacchetti non si limita più al solo dump sequenziale su disco via libpcap, ma si divide in tre livelli operativi:
- Analisi Forense e Protocol Decoding: BestDefense
- Wireshark & tcpdump: Restano lo standard de facto assoluto per l’analisi interattiva e la risoluzione di problemi puntuali. Wireshark include ormai decodificatori maturi per HTTP/3, QUIC, WireGuard e meccanismi avanzati per iniettare chiavi di sessione TLS (SSLKEYLOGFILE). ET CIO
- Network Analysis a Livello Metadati & Threat Detection:
- Zeek (ex Bro): Non memorizza interi payload ma trasforma il traffico grezzo in metadati strutturati ad altissima densità informativa (sessioni TLS, impronte JA3/JA4, transazioni DNS, SMB, SSH). È il pilastro per l’invio di telemetria di rete verso SIEM (Elasticsearch, OpenSearch, Wazuh). BestDefense+ 1
- Suricata: Ha definitivamente superato Snort negli ambienti Linux moderni grazie alla sua architettura nativamente multi-thread, al supporto eBPF/XDP per il bypass dei pacchetti noti a velocità di linea e al parser Rust per i protocolli ad alto livello. LinuxTeck
- Arkime (ex Moloch): Lo strumento open source standard per la cattura full-packet indicizzata su larga scala con interfaccia web per investigazioni retroattive. BestDefense
- ntopng / nDPI: Ha rimpiazzato i vecchi
ntopebmonper la telemetria L7 in tempo reale, introducendo l’analisi del traffico cifrato tramite impronte comportamentali ed eBPF. BestDefense
3. Il cambio di paradigma su Linux: da libpcap a eBPF/XDP
Se il tuo background è incentrato su iptables, syslog e socket RAW tradizionali (libpcap), la vera rottura tecnologica nel kernel Linux odierno è rappresentata da:
- eBPF (Extended Berkeley Packet Filter): Permette di eseguire codice sandboxato ad altissima velocità nello spazio kernel senza modificare i sorgenti del kernel o caricare moduli instabili. DEV Community
- XDP (eXpress Data Path): Intercetta i pacchetti direttamente a livello di driver di rete della scheda (NIC) prima che vengano allocate le strutture
sk_buffdel kernel. Consente di applicare filtri packet-drop anti-DDoS e reindirizzamento a decine di milioni di pacchetti al secondo su hardware standard. - Observability e Runtime Security: Strumenti come Cilium, Tetragon e Falco correlano il pacchetto di rete non solo con IP/porta, ma istantaneamente con il PID del processo, il namespace, il descrittore del file e l’eventuale container che ha generato la chiamata di sistema.
Sintesi dello stack attuale
| Scenario d’uso | Strumenti di riferimento oggi |
|---|---|
| Gateway NGFW / Bastione perimetrale | OPNsense (con Zenarmor + Suricata) o IPFire |
| Ispezione L7 / IDS-IPS ad alte prestazioni | Suricata (in modalità multithread / AF_PACKET / eBPF) |
| Network Security Monitoring & Log di sessione | Zeek + stack Elastic/OpenSearch |
| Cattura e ricerca Full-Packet (PCAP) | Arkime (infrastruttura) / Wireshark (debug locale) |
| Ispezione a bassissimo overhead a livello host | eBPF / XDP (con strumenti come Tetragon, Cilium o script bpftrace) |
Confronta l’efficacia e le prestazioni di OPNsense rispetto a un gateway Linux personalizzato basato su nftables e Suricata.
Il confronto tra un’appliance chiavi in mano come OPNsense (basata su FreeBSD/HardenedBSD e packet filter pf) e un gateway Linux bare-metal personalizzato (basato su nftables e Suricata) mette a nudo il compromesso storico tra comodità operativa/governance centralizzata e prestazioni grezze/densità di throughput.
1. Architettura del Packet Processing e Prestazioni
La differenza fondamentale risiede nel modo in cui i due kernel gestiscono lo stack di rete e l’I/O ad alto carico.
- Linux (nftables + Netfilter):
- Scalabilità multi-core: Il networking subsystem del kernel Linux scala in modo più lineare su CPU multi-core moderne grazie a meccanismi avanzati di Receive Side Scaling (RSS), RPS/RFS e all’allocazione efficiente dei descrittori di rete.
- Efficienza delle regole:
nftablescompila i set di regole in un bytecode eseguito da una macchina virtuale interna al kernel. L’uso nativo di tabelle hash, intervalli (range) e mappe eterogenee (es. concatenazioni IP-porta in una sola lookup O(1)) riduce drasticamente i cicli CPU rispetto al processamento sequenziale. - Zero-Copy e bypass kernel: Linux supporta nativamente socket ad altissima velocità come
AF_PACKET(in modalitàPACKET_MMAP),AF_XDPe hook eBPF/XDP. Questo consente di scartare pacchetti malevoli o inviarli a Suricata prima ancora che il kernel allochi la struttura datisk_buff.
- FreeBSD/OPNsense (pf):
- Architettura di pf: Il packet filter
pfsu BSD è storicamente elegante e robusto, ma soffre di un overhead di lock a livello di stato delle connessioni (state table locking) più marcato quando si sale a decine di gigabit o a centinaia di migliaia di nuove connessioni al secondo. - Driver di rete: Sebbene FreeBSD sia eccellente su schede di rete di classe server (come Intel
ixgbeoice), il supporto per NIC di fascia consumer (es. Realtek 2.5GbE) o hardware 10/25/100GbE di ultimissima generazione è spesso meno ottimizzato o in ritardo rispetto al kernel Linux.
- Architettura di pf: Il packet filter
- Verdetto prestazioni grezze: A parità di hardware (in particolare su link 10Gbps+ o carichi con milioni di PPS), il gateway Linux offre una latenza inferiore, un throughput di routing/NAT significativamente più alto e un utilizzo della CPU più ridotto.
2. Integrazione del motore IPS (Suricata)
Il modo in cui Suricata intercetta e analizza il traffico determina l’impatto prestazionale dell’ispezione Deep Packet Inspection:
- In OPNsense (via Netmap):
- OPNsense integra Suricata sfruttando il framework Netmap per l’I/O veloce a livello utente in modalità inline IPS.
- Punto debole: Netmap richiede un supporto dedicato e privo di bug da parte dei driver della scheda di rete. Se il driver della NIC non implementa Netmap alla perfezione, si possono verificare memory leak, kernel panic o instabilità nei cambi di stato delle interfacce.
- Nel gateway Linux personalizzato (via AF_PACKET o NFQUEUE / eBPF):
- Suricata su Linux brilla in modalità AF_PACKET inline con supporto multi-queue (FANOUT): ogni coda di ricezione hardware della NIC viene mappata su un thread dedicato di Suricata, azzerando i cambi di contesto.
- È possibile abilitare il bypass via eBPF: una volta che Suricata ha classificato un flusso cifrato come lecito (es. uno stream video o una sincronizzazione file affidabile), delega la gestione del flusso direttamente a XDP/eBPF nel kernel, eliminando l’overhead di analisi sui pacchetti successivi.
3. Gestione, Manutenzione e Sicurezza Operativa
Le prestazioni non sono l’unico parametro; il costo operativo è l’elemento determinante nella scelta:
- OPNsense:
- Ciclo di vita: Aggiornamenti bi-settimanali del firmware, snapshot ZFS con possibilità di rollback immediato al bootloader (boot environments) in caso di aggiornamento fallito.
- Governance integrata: Generazione automatica di certificati Let’s Encrypt, gestione utenti, configurazione visuale di tunnel WireGuard/IPsec, backup cifrati e integrazione out-of-the-box con Zenarmor per il controllo Layer 7.
- Visibilità: Dashboard pronte all’uso, grafici di carico e reportistica integrata senza necessità di configurare collector esterni.
- Linux custom (nftables + Suricata):
- Complessità sistemistica: Richiede la scrittura e il versionamento manuale dei file di configurazione (
/etc/nftables.conf,suricata.yaml), la gestione dei set dinamici (nftseto integrazione conipset/fail2ban) e la manutenzione dei download dei ruleset di Suricata (es. tramitesuricata-updatein cron). - Stack di monitoraggio separato: Per avere visibilità comparabile a OPNsense, è necessario configurare pipeline esterne: ad esempio esportare i log
eve.jsondi Suricata su uno stack centralizzato (Vector/Logstash verso Elasticsearch o Graylog) e visualizzare le metriche con Prometheus/Grafana.
- Complessità sistemistica: Richiede la scrittura e il versionamento manuale dei file di configurazione (
Confronto Tecnico di Sintesi
| Caratteristica | OPNsense (FreeBSD / pf) | Linux Gateway (nftables + Suricata) |
|---|---|---|
| Throughput Routing & NAT | Molto buono fino a 2.5–10 Gbps; fatica a scalare oltre con hardware commodity | Eccellente; scala linearmente fino a saturazione del bus (10–40+ Gbps) |
| DPI / IPS (Suricata) | Inline tramite Netmap (dipendente dalla qualità dei driver BSD) | Inline nativo tramite AF_PACKET + eBPF bypass (massima stabilità ed efficienza) |
| Filtraggio pacchetti L3/L4 | Sintassi pf leggibile, gestione stati robusta ma con lock centralizzati | nftables con lookup O(1), mappe composite e supporto a filtri XDP stateless |
| Layer 7 / NGFW | Facile tramite plugin Zenarmor (DPI, categorie Web, controlli applicativi) | Richiede Suricata con regole L7/Lua dedicate o proxy Layer 7 a monte |
| Configurazione & Gestione | GUI Web completa, API REST, gestione certificati e VPN integrata | CLI pura, script Bash/Ansible, gestione manuale di WireGuard e routing |
| Disaster Recovery | Rollback istantaneo a livello di bootloader grazie a snapshot ZFS | Dipendente dalla strategia di automazione dell’infrastruttura (es. Ansible / Git) |
Indicazioni per la scelta
- Scegli OPNsense se: Hai bisogno di un bastione perimetrale completo, gestibile da un unico pannello web, con un motore NGFW Layer 7 pronto (Zenarmor) e tempi di messa in produzione minimi, su linee fino a 1–2.5 Gbps.
- Scegli il gateway Linux personalizzato se: Operi su uplink multi-gigabit (10G/25G), hai a che fare con hardware x86 recente o schede di rete che beneficiano del supporto driver nativo di Linux, desideri sfruttare eBPF/XDP per mitigazione DoS a velocità di linea e preferisci gestire l’infrastruttura come codice (IaC/Ansible).
Mostrami una configurazione minimale ma performante di nftables con gestione di set dinamici e interfaccia con Suricata in AF_PACKET.
Architettura della soluzione
Nel deployment con Suricata inline IPS via AF_PACKET, Suricata agisce come bridge trasparente a livello 2 tra due interfacce fisiche (es. eth0 WAN ed eth1 LAN), oppure su una coppia di interfacce virtuali (veth/MACVLAN).
Quando Suricata intercetta il traffico in modalità bridge AF_PACKET, i pacchetti vengono acquisiti direttamente dal ring buffer della scheda, processati dai worker multithread e, se non scartati (drop), reiniettati sulla scheda opposta. Lo stack Netfilter/nftables interviene a livello host prima e dopo il processing di rete per:
- Gestire lo stateful filtering (L3/L4) con lookup O(1).
- Bloccare istantaneamente IP o subnet abusive tramite set dinamici ad alta efficienza con timeout automatico (evitando memory leak).
- Eseguire NAT/masquerading per la subnet interna.
1. Configurazione performante di /etc/nftables.conf
Questa configurazione sfrutta le mappe concatenate e i set con flag dynamic e timeout per l’auto-scadenza degli host malevoli.
Snippet di codice
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
# Set dinamico per IP bloccati con timeout automatico
set dynamic_denylist {
type ipv4_addr
flags dynamic, timeout
timeout 1h
size 65535
}
# Set per porte TCP consentite sul bastione stesso
set bastion_tcp_services {
type inet_service
elements = { 22 }
}
# Catena di ingresso verso l'host stesso
chain input {
type filter hook input priority filter; policy drop;
# 1. Loopback
iif "lo" accept
# 2. Connessioni già tracciate (fast-path hardware-friendly)
ct state established,related accept
ct state invalid drop
# 3. Blocco immediato se presente nella blacklist dinamica (lookup O(1))
ip saddr @dynamic_denylist drop
# 4. Accesso ai servizi di gestione del bastione
iif "eth1" tcp dport @bastion_tcp_services ct state new accept
# 5. ICMP essenziale (ping limitato per evitare flood)
ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } limit rate 5/second accept
}
# Catena di transito (Routing / Forwarding)
chain forward {
type filter hook forward priority filter; policy drop;
# Blocco preventivo da denylist anche in transito
ip saddr @dynamic_denylist drop
ip daddr @dynamic_denylist drop
# Stateful forwarding
ct state established,related accept
ct state invalid drop
# Consenti traffico in uscita dalla LAN (eth1 -> eth0)
iif "eth1" oif "eth0" accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# Masquerade su WAN per il traffico originato da LAN
iif "eth1" oif "eth0" masquerade
}
}
Operazioni sui set dinamici da riga di comando
Puoi aggiungere e verificare dinamicamente gli host (manualmente o tramite script integrati con i log eve.json di Suricata):
- Aggiungere un IP con timeout specifico:Bash
nft add element inet filter dynamic_denylist { 198.51.100.42 timeout 30m } - Verificare il set e il tempo residuo per ciascun elemento:Bash
nft list set inet filter dynamic_denylist
2. Configurazione di Suricata (suricata.yaml) in modalità AF_PACKET Inline
Nel file /etc/suricata/suricata.yaml, la sezione af-packet deve essere configurata per agganciare le code hardware della scheda (cluster-type: cluster_flow) con ring buffer a memoria mappata (mmap per azzerare le copie in userspace).
YAML
af-packet:
# Interfaccia Esterna (WAN)
- interface: eth0
threads: auto
cluster-id: 99
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
mmap-locked: yes
tpacket-v3: yes
ring-size: 2048
block-size: 32768
# Inoltro diretto verso l'interfaccia interna
copy-mode: ips
copy-iface: eth1
# Interfaccia Interna (LAN)
- interface: eth1
threads: auto
cluster-id: 98
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
mmap-locked: yes
tpacket-v3: yes
ring-size: 2048
block-size: 32768
# Inoltro diretto verso l'interfaccia esterna
copy-mode: ips
copy-iface: eth0
3. Tuning hardware e offload delle schede di rete
Per far operare Suricata in modalità inline senza corruzione del checksum o disallineamento dei pacchetti, è obbligatorio disabilitare gli offload hardware LRO/GRO sulle interfacce coinvolte.
Esegui (o inserisci nello script di avvio di rete):
Bash
# Disabilita Large Receive Offload e Generic Receive Offload su entrambe le interfacce
ethtool -K eth0 gro off lro off tso off gso off
ethtool -K eth1 gro off lro off tso off gso off
# Aumenta i buffer di ricezione/trasmissione hardware della NIC al massimo supportato
ethtool -G eth0 rx 4096 tx 4096
ethtool -G eth1 rx 4096 tx 4096
4. Flusso operativo di mitigazione
- L1/L2: Il traffico arriva sulla NIC (
eth0); i ring buffer AF_PACKET trasferiscono i chunk di memoria direttamente allo spazio di memoria condiviso di Suricata (use-mmap: yes). - L7 (Suricata): I thread analizzano i protocolli applicativi e le firme IDS. Se scatta una regola
drop, il pacchetto viene scartato e registrato su/var/log/suricata/eve.json. - Bridge/Inoltro: I pacchetti ammessi vengono reiniettati sulla seconda interfaccia (
eth1). - L3/L4 (nftables): Gestisce il routing, il masquerading (NAT) e intercetta gli IP recidivi tramite il set
dynamic_denylist, scartandoli prima che impegnino risorse di calcolo a livello utente.
Spiegami in dettaglio come configurare il bypass dei flussi cifrati in Suricata sfruttando eBPF e XDP su Linux.
Il bypass via eBPF/XDP (chiamato anche eBPF Flow Bypass) è una delle ottimizzazioni prestazionali più incisive per Suricata su Linux.
Quando un flusso di rete non richiede ulteriore ispezione L7 (ad esempio una sessione TLS/HTTPS validata dopo l’handshake, un tunnel WireGuard o un grosso trasferimento dati già classificato come sicuro), Suricata scrive i metadati del flusso (5-tuple) in una BPF hash map condivisa con il kernel. Da quel momento, il programma XDP agganciato al driver della scheda di rete intercetta i pacchetti successivi e li inoltra direttamente a velocità di linea, evitando completamente il passaggio verso lo userspace e l’allocazione delle strutture sk_buff.
Prerequisiti di Sistema
- Kernel Linux: Versione 5.4 o superiore (consigliato 6.x con supporto eBPF completo).
- Pacchetti e librerie:
clang,llvm,libbpf-dev,libelf-dev,iproute2. - Suricata: Compilato con supporto eBPF abilitato (
--enable-ebpf). Su distribuzioni moderne (Ubuntu/Debian via repository OISF o pacchetti ufficiali), il supporto è solitamente compilato di serie.
Verifica il supporto da terminale:
Bash
suricata --build-info | grep -i ebpf
# Output atteso: eBPF support: yes
1.Compilare il programma eBPF di Suricata:Kernel space filter.
Suricata fornisce i sorgenti C per i moduli eBPF e XDP all’interno del proprio albero sorgente o in /usr/share/suricata/ebpf/ (a seconda del pacchetto della distribuzione).
Se i binari .o non sono precompilati, spostati nella directory del codice sorgente eBPF e compilali con Clang/LLVM:
Bash
cd /usr/share/suricata/ebpf # o path ai sorgenti: suricata/ebpf/
clang -O2 -g -target bpf -Wall -c xdp_filter.c -o /etc/suricata/ebpf/xdp_filter.o
clang -O2 -g -target bpf -Wall -c lb.c -o /etc/suricata/ebpf/lb.o
Verifica del successo: Il file /etc/suricata/ebpf/xdp_filter.o deve esistere e l’output di file /etc/suricata/ebpf/xdp_filter.o deve confermare un file oggetto ELF 64-bit per architettura BPF.
2.Configurare lo stream bypass in suricata.yaml:suricata.yaml.
Modifica /etc/suricata/suricata.yaml per abilitare l’engine di stream bypass sia a livello generale che all’interno delle interfacce af-packet.
Nel blocco globale di configurazione dello stream:
YAML
stream:
memcap: 1gb
checksum-validation: yes
inline: yes
reassembly:
memcap: 2gb
depth: 1mb
toserver-chunk-size: 2560
toclient-chunk-size: 2560
# Abilita il motore di bypass
bypass: yes
Nel blocco af-packet, sostituisci la configurazione base con i parametri XDP e le mappe BPF:
YAML
af-packet:
- interface: eth0
threads: auto
cluster-id: 99
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
tpacket-v3: yes
ring-size: 2048
block-size: 32768
copy-mode: ips
copy-iface: eth1
# Integrazione eBPF / XDP
ebpf: yes
ebpf-filter-file: /etc/suricata/ebpf/xdp_filter.o
xdp-mode: driver # Opzioni: driver (nativo) o generic (fallback CPU)
bypass: yes
- interface: eth1
threads: auto
cluster-id: 98
cluster-type: cluster_flow
defrag: yes
use-mmap: yes
tpacket-v3: yes
ring-size: 2048
block-size: 32768
copy-mode: ips
copy-iface: eth0
# Integrazione eBPF / XDP
ebpf: yes
ebpf-filter-file: /etc/suricata/ebpf/xdp_filter.o
xdp-mode: driver
bypass: yes
Nota su xdp-mode: L’impostazione driver esegue il codice all’interno del driver della NIC (massime prestazioni). Se la tua scheda non lo supporta, passa temporaneamente a generic (funziona ovunque ma interviene poco dopo nello stack kernel).
Verifica del successo: Esegui un test di validazione sintattica:
Bash
suricata -T -c /etc/suricata/suricata.yaml
L’output deve terminare con Configuration provided was successfully parsed.
3.Istruire Suricata al bypass dei flussi cifrati:Signature rules.
Il bypass non avviene automaticamente per qualsiasi connessione; è necessario definire quali flussi contrassegnare con la direttiva bypass.
Crea o modifica un file di regole locali (es. /etc/suricata/rules/bypass.rules):
suricata
# 1. Bypass del traffico TLS una volta convalidato l'handshake
pass tls any any -> any any (msg:"Bypass established TLS sessions"; tls.subject:"*"; flow:established; bypass; sid:9900001; rev:1;)
# 2. Bypass per tunnel cifrati WireGuard noti (es. porta 51820)
pass udp any any -> any 51820 (msg:"Bypass WireGuard Tunnel"; flow:stateless; bypass; sid:9900002; rev:1;)
# 3. Bypass per trasferimenti HTTPS basati su SNI fidato (es. video streaming / backup)
pass tls any any -> any any (msg:"Bypass trusted SNI"; tls.sni; content:"download.videolan.org"; endswith; flow:established; bypass; sid:9900003; rev:1;)
Assicurati che /etc/suricata/rules/bypass.rules sia incluso nella direttiva rule-files: del tuo suricata.yaml.
Verifica del successo: Riavvia il servizio Suricata e controlla /var/log/suricata/suricata.log per accertarti che il ruleset sia caricato senza errori di parsing.
4.Verifica del funzionamento a runtime:bpftool e statistiche.
Per verificare che il programma XDP sia caricato sulle schede e che i pacchetti vengano effettivamente bypassati:
- Controlla il caricamento XDP sull’interfaccia:
Bash
ip link show dev eth0
Dovresti notare la dicitura xdp o xdpdrv con l’ID del programma agganciato.
- Ispeziona la BPF Map dei flussi:Usa l’utility del kernel
bpftoolper vedere le connessioni memorizzate nella tabella hash eBPF:
Bash
bpftool map show
bpftool map dump name flow_table_v4
- Verifica le metriche nei log di Suricata:Controlla il file
/var/log/suricata/stats.logcercando i contatori di bypass:
Bash
grep "capture.kernel_packets" /var/log/suricata/stats.log
grep "flow_bypassed" /var/log/suricata/stats.log
Verifica del successo: Il contatore flow_bypassed.pkts e flow_bypassed.bytes in stats.log deve incrementarsi mentre si eseguono trasferimenti dati pesanti (es. curl https://... o speedtest).
Gestione del ciclo di vita dei flussi bypassati
La BPF map memorizza la 5-tuple e un timestamp. Suricata continua a monitorare periodicamente lo stato delle connessioni: quando rileva la chiusura della connessione (tramite pacchetti TCP FIN/RST che continuano a essere monitorati o per timeout di inattività impostato in suricata.yaml), Suricata emette una syscall per rimuovere la chiave dalla hash map eBPF, liberando memoria per le nuove sessioni.
Come posso esportare i contatori di bypass di Suricata ed eBPF verso Prometheus e Grafana?
Per esportare le metriche di bypass di Suricata ed eBPF verso Prometheus hai a disposizione due architetture:
- L’exporter nativo o dedicato di Suricata (
eve.json/ Socket): Suricata registra periodicamente gli eventistatscontenenti tutti i contatori del motore (flow_bypassed, memcap, drop) in formato JSON. Strumenti come l’exporter dedicato in Go (suricata-exporter) o un pipeline agent leggero come Vector o Telegraf leggono questo stream e lo espongono in formato Prometheus. - Exporter di metriche kernel/XDP (
ebpf_exporterdi Cloudflare): Legge direttamente le BPF Maps in kernel space per contare i pacchetti intercettati e inoltrati a livello XDP, garantendo metriche indipendenti dal logging di Suricata.
La soluzione standard, a basso overhead e più flessibile per un gateway di produzione, consiste nell’usare il logger eve-log.stats di Suricata intercettato da suricata-exporter (o Vector), combinato con node_exporter per i contatori di rete della NIC.
1.Abilitare l’output delle statistiche in eve-log:suricata.yaml.
Assicurati che Suricata scriva gli snapshot di statistiche nel file strutturato eve.json.
Apri /etc/suricata/suricata.yaml e verifica la sezione outputs:
YAML
outputs:
- eve-log:
enabled: yes
filetype: regular # oppure 'unix_stream' se colleghi un demone direttamente a socket
filename: eve.json
types:
- alert
- drop
- stats:
totals: yes # accumula i totali
threads: no # evita payload enormi se non ti servono statistiche per-core
deltas: no
Imposta l’intervallo di campionamento delle statistiche (es. ogni 10 secondi per allinearlo allo scrape di Prometheus):
YAML
stats:
enabled: yes
interval: 10
Ricarica la configurazione di Suricata:
Bash
suricatasc -c reload-rules
# oppure: systemctl restart suricata
Verifica del successo: Controlla che vengano generati record di tipo stats eseguendo:
Bash
tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="stats") | .stats.flow_bypassed'
Dovresti visualizzare l’oggetto JSON con le chiavi pkts, bytes e closed.
2.Installare e configurare suricata-exporter:Servizio di scraping L7.
Il binario suricata-exporter esegue il tailing su eve.json (oppure legge dal socket UNIX) ed espone le metriche sulla porta :9917/metrics.
- Scarica o compila il binario:
Bash
# Esempio scaricando la release precompilata (adatta ad architetture x86_64 o arm64)
wget https://github.com/dalmar/suricata-exporter/releases/latest/download/suricata-exporter-linux-amd64 -O /usr/local/bin/suricata-exporter
chmod +x /usr/local/bin/suricata-exporter
- Crea l’unità systemd
/etc/systemd/system/suricata-exporter.service:
Ini, TOML
[Unit]
Description=Suricata Prometheus Exporter
After=network.target suricata.service
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/suricata-exporter --eve-path=/var/log/suricata/eve.json --listen-address=:9917
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
- Abilita e avvia il servizio:
Bash
systemctl daemon-reload
systemctl enable --now suricata-exporter
Verifica del successo: Interroga l’endpoint metrics via curl:
Bash
curl -s http://localhost:9917/metrics | grep suricata_flow_bypassed
Dovresti vedere metriche come suricata_flow_bypassed_pkts_total e suricata_flow_bypassed_bytes_total.
3.Configurare il job di scraping su Prometheus:Target definition.
Aggiungi il target del bastione nel file di configurazione di Prometheus (/etc/prometheus/prometheus.yml):
YAML
scrape_configs:
- job_name: 'suricata'
scrape_interval: 10s
static_configs:
- targets: ['127.0.0.1:9917'] # O l'IP di gestione del bastione
labels:
host: 'gateway-core'
role: 'ngfw-suricata'
Ricarica Prometheus:
Bash
curl -X POST http://localhost:9090/-/reload
Verifica del successo: Nell’interfaccia web di Prometheus (Status -> Targets), il target suricata deve risultare in stato UP.
4.Costruire le query e la dashboard in Grafana:Dashboard & PromQL.
Crea una dashboard in Grafana per visualizzare il rapporto tra traffico ispezionato L7 e traffico scaricato in eBPF/XDP.
Query PromQL chiave per i pannelli:
- Rapporto di Throughput Bypassato vs Ispezionato (Bytes/sec):
promql
# Throughput bypassato (eBPF/XDP)
rate(suricata_flow_bypassed_bytes_total[1m]) * 8
promql
# Throughput ispezionato da Suricata a livello utente
rate(suricata_capture_kernel_bytes_total[1m]) * 8
- Percentuale di pacchetti bypassati (Offload Ratio):
promql
(
rate(suricata_flow_bypassed_pkts_total[1m])
/
(rate(suricata_capture_kernel_packets_total[1m]) + rate(suricata_flow_bypassed_pkts_total[1m]))
) * 100
- Flussi bypassati attivi (Stima flussi aperti al secondo):
promql
rate(suricata_flow_bypassed_closed_total[1m])
- Pacchetti scartati o persi (Drop rate dell’engine):
promql
rate(suricata_capture_kernel_drops_total[1m])
Verifica del successo: Genera traffico TLS pesante da un host client (es. curl -k [https://speed.hetzner.de/1GB.bin](https://speed.hetzner.de/1GB.bin) -o /dev/null). Il pannello in Grafana deve mostrare una netta predominanza di banda sul contatore bypass rispetto al volume ispezionato dai thread L7.
Opzione Avanzata: Conteggio diretto delle BPF Maps via Cloudflare ebpf_exporter
Se desideri misurare l’I/O direttamente dai contatori del kernel gestiti dal file xdp_filter.o senza dipendere dall’intervallo di flush di eve.json, puoi installare ebpf_exporter:
- Scrivi un file di configurazione BPF YAML (es.
/etc/ebpf_exporter/suricata_xdp.yaml):YAMLprograms: - name: xdp_suricata_flow metrics: counters: - name: xdp_bypass_packets help: Pacchetti processati direttamente via XDP bypass table: flow_table_v4 kprobes: {} - Questo consente di plottare la latenza e i pacchetti scartati/inoltrati con risoluzione al sub-secondo, ideale per verificare se schede 10G/25G stanno saturando i ring buffer di rete.
Mostrami come usare Vector per inviare metriche ed alert di Suricata contemporaneamente a Prometheus ed Elasticsearch.
Usare Vector (scritto in Rust, ad altissime prestazioni e bassissimo footprint di memoria) è una scelta ideale su un gateway/bastione rispetto a Logstash o Fluentd: con pochissimi megabyte di RAM può gestire decine di migliaia di eventi al secondo senza rubare cicli CPU al motore IPS.
In questa architettura, Vector:
- Legge
/var/log/suricata/eve.jsonin streaming. - Esegue il parsing JSON con il linguaggio nativo VRL (Vector Remap Language).
- Instrada gli eventi:
- Gli eventi di tipo
alert(e opzionalmentedrop) vengono normalizzati e inviati via HTTP a Elasticsearch (o OpenSearch). - Gli eventi di tipo
statsvengono trasformati in metriche aggregate ed esposti sull’endpoint/metricsper lo scrape di Prometheus.
- Gli eventi di tipo
Configurazione Completa (/etc/vector/vector.yaml)
YAML
# ==============================================================================
# SORGENTE DATI
# ==============================================================================
sources:
suricata_eve:
type: file
include:
- /var/log/suricata/eve.json
read_from: end
# Opzionale: evita di rileggere file giganti dopo rotazione log
max_line_bytes: 1048576
# ==============================================================================
# TRASFORMAZIONI E ROUTING
# ==============================================================================
transforms:
# 1. Parsing JSON iniziale
parse_eve:
type: remap
inputs:
- suricata_eve
source: |
. = parse_json!(string!(.message))
# 2. Separazione dei flussi in base a event_type
split_eve:
type: route
inputs:
- parse_eve
route:
alerts: '.event_type == "alert" || .event_type == "drop"'
stats: '.event_type == "stats"'
# 3. Normalizzazione degli alert per Elasticsearch
format_alerts:
type: remap
inputs:
- split_eve.alerts
source: |
# Estrai il timestamp originale di Suricata
.@timestamp = parse_timestamp!(.timestamp, format: "%Y-%m-%dT%H:%M:%S.%f%z")
# Normalizza i campi principali per facilitare le query in Kibana
.signature = .alert.signature
.severity = .alert.severity
.action = .alert.action
.category = .alert.category
# Rimuovi campi ridondanti o troppo verbosi se non necessari
del(.message)
# 4. Estrazione metriche da stats.log per Prometheus
extract_metrics:
type: remap
inputs:
- split_eve.stats
source: |
# Creazione delle metriche Prometheus usando la funzione metric()
# Metrica 1: Pacchetti bypassati (eBPF/XDP)
if exists(.stats.flow_bypassed.pkts) {
. = {
"name": "suricata_flow_bypassed_pkts_total",
"kind": "absolute",
"counter": { "value": to_float!(.stats.flow_bypassed.pkts) },
"tags": { "host": get_hostname!() }
}
}
# Metrica 2: Byte bypassati (eBPF/XDP)
if exists(.stats.flow_bypassed.bytes) {
. = {
"name": "suricata_flow_bypassed_bytes_total",
"kind": "absolute",
"counter": { "value": to_float!(.stats.flow_bypassed.bytes) },
"tags": { "host": get_hostname!() }
}
}
# Metrica 3: Pacchetti totali processati dal kernel
if exists(.stats.capture.kernel_packets) {
. = {
"name": "suricata_capture_kernel_packets_total",
"kind": "absolute",
"counter": { "value": to_float!(.stats.capture.kernel_packets) },
"tags": { "host": get_hostname!() }
}
}
# Metrica 4: Pacchetti scartati a livello capture (drop/loss)
if exists(.stats.capture.kernel_drops) {
. = {
"name": "suricata_capture_kernel_drops_total",
"kind": "absolute",
"counter": { "value": to_float!(.stats.capture.kernel_drops) },
"tags": { "host": get_hostname!() }
}
}
# ==============================================================================
# DESTINAZIONI (SINKS)
# ==============================================================================
sinks:
# Invio Alert a Elasticsearch / OpenSearch
elasticsearch_out:
type: elasticsearch
inputs:
- format_alerts
endpoints:
- "http://10.0.0.50:9200" # Inserisci l'IP del cluster Elastic
mode: bulk
bulk:
index: "suricata-alerts-%Y.%m.%d"
# Configurazione autenticazione se abilitata
auth:
strategy: basic
user: "elastic"
password: "YourStrongPasswordHere"
compression: gzip
batch:
max_events: 1000
timeout_secs: 5
# Endpoint scraping Prometheus per le metriche
prometheus_out:
type: prometheus_exporter
inputs:
- extract_metrics
address: "0.0.0.0:9090" # Vector fa da server metrics Prometheus
default_namespace: "suricata"
Procedura di Messa in Produzione
1.Installare Vector:Installazione.
Su distribuzioni Debian/Ubuntu o derivate, Vector è installabile con il repository ufficiale di Timber.io / Datadog:
Bash
curl -1sLf 'https://repositories.timber.io/public/vector/cfg/setup/bash.deb.sh' | sudo -E bash
sudo apt-get install vector
2.Configurare i permessi su eve.json:Permessi.
Vector gira per default sotto l’utente vector. Assicurati che l’utente abbia i permessi di lettura sul file e sulla directory di log:
Bash
usermod -aG suricata vector # aggiunge vector al gruppo suricata se presente
chmod 750 /var/log/suricata
chmod 640 /var/log/suricata/eve.json
3.Validare la configurazione e avviare il servizio:Validazione e Avvio.
Vector include un linter che testa il parsing VRL e la sintassi prima del restart:
Bash
vector validate /etc/vector/vector.yaml
Se la sintassi è valida:
Bash
systemctl restart vector
systemctl status vector
Verifica del successo:
- Prometheus metrics: Interroga l’endpoint con
curl http://localhost:9090/metrics | grep suricata_flow_bypassed. - Elasticsearch indexing: Controlla che l’indice giornaliero venga creato:
Bash
curl -u elastic:YourStrongPasswordHere http://10.0.0.50:9200/_cat/indices/suricata-alerts-*?v
Vantaggi di questa Architettura
- Zero Memory Bloat: Vector alloca tipicamente < 60 MB di RSS anche durante picchi di decine di migliaia di eventi.
- Resilienza con Backpressure: Se Elasticsearch è temporaneamente non raggiungibile o saturo di I/O, Vector gestisce buffer su disco (
buffer.type: disk) evitando perdite di alert senza impattare la stabilità di Suricata. - Disaccoppiamento totale: Suricata si occupa unicamente di ispezionare pacchetti ed emettere il JSON in kernel/userspace; tutta la logica di smistamento, arricchimento e compatibilità verso i sistemi di telemetria è gestita all’esterno.