Filtra il traffico verso il router con nftables e limita ICMP

Filtra il traffico verso il router con nftables e limita ICMP

Un attacco flood diretto all’indirizzo del router stesso può costringere la sua CPU a elaborare traffico che non dovrebbe raggiungere i servizi di controllo e gestione. In Linux, una policy di ingresso di nftables permette di accettare ciò che serve al router e scartare il resto; il traffico che attraversa soltanto l’apparato segue un altro percorso di filtraggio.

L’esempio configura BGP per un peer, SSH e SNMP per una rete di gestione e il ping con un limite di frequenza. Usa 192.0.2.1 e 2001:db8:ffff::1 come indirizzi del router, 192.0.2.2 e 2001:db8:ffff::2 per il peer e 192.0.2.0/27 e 2001:db8:100::/48 per le reti di gestione. Sostituiscili con quelli del tuo ambiente prima di applicare le regole.

Il problema: proteggere ciò che termina sul router

Il punto chiave è distinguere tra traffico di transito e traffico destinato all’apparato stesso. In nftables, la catena con hook input elabora i pacchetti consegnati al sistema locale; forward riguarda i pacchetti che il sistema inoltra a un altro host. Questa policy opera solo su input, quindi non intende sostituire le regole di transito.

L’idea del control-plane policing (CoPP) consiste nel classificare il traffico che può raggiungere la CPU e applicare un trattamento diverso a ciascuna classe. In un router Linux, il filtro di ingresso è un modo per implementare questa logica nel firewall. La sequenza sarà: impostare una policy di negazione, mantenere le connessioni stabilite, consentire i protocolli indispensabili, aprire i servizi solo alle origini autorizzate e limitare le richieste echo.

flowchart TD
    A["Paquete recibido"] --> B{"¿Va al router?"}
    B -->|"No"| C["Ruta de tránsito"]
    B -->|"Sí"| D{"¿Está permitido?"}
    D -->|"Sí"| E["Aceptar o limitar"]
    D -->|"No"| F["Contar y descartar"]

Creare la policy di ingresso

1. Definisci i peer e le reti di gestione

I set raccolgono gli indirizzi che possono avviare sessioni di routing o gestire l’apparato. Nell’esempio, BGP è limitato a un peer IPv4 e uno IPv6. La gestione consente SSH dalle reti indicate e SNMP dalla rete IPv4 di gestione. Non lasciare indirizzi di esempio in produzione: configura quelli reali prima di continuare.

2. Consenti ciò che serve e scarta il resto

Salva questo ruleset, per esempio come router.nft. La policy predefinita della catena è drop. Per prima cosa vengono consentite le connessioni stabilite o correlate, scartati gli stati non validi e accettato il traffico di loopback. Seguono le eccezioni per il rilevamento dei peer, i protocolli di routing e la gestione.

L’elenco ICMPv6 include messaggi di rilevamento e di errore di rete, tra cui packet-too-big. L’esempio non limita il rilevamento dei vicini: restringerlo può interferire con la risoluzione degli indirizzi sotto carico. ARP, invece, non viene filtrato in questa tabella inet; richiede regole nella famiglia arp.

table inet cp {
    set peers4 {
        type ipv4_addr
        elements = { 192.0.2.2 }
    }

    set peers6 {
        type ipv6_addr
        elements = { 2001:db8:ffff::2 }
    }

    set mgmt4 {
        type ipv4_addr
        flags interval
        elements = { 192.0.2.0/27 }
    }

    set mgmt6 {
        type ipv6_addr
        flags interval
        elements = { 2001:db8:100::/48 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        ct state established,related accept
        ct state invalid drop
        iif lo accept

        # ICMPv6 necessario per i peer e gli errori di routing
        meta l4proto ipv6-icmp icmpv6 type {
            nd-router-solicit,
            nd-router-advert,
            nd-neighbor-solicit,
            nd-neighbor-advert,
            packet-too-big,
            destination-unreachable,
            time-exceeded,
            parameter-problem
        } accept
        ip protocol icmp icmp type {
            destination-unreachable,
            time-exceeded
        } accept

        # BGP, OSPFv3 da indirizzi link-local e BFD
        ip saddr @peers4 tcp dport 179 accept
        ip6 saddr @peers6 tcp dport 179 accept
        ip6 saddr fe80::/10 ip6 nexthdr 89 accept
        ip saddr @peers4 udp dport { 3784, 4784 } accept

        # Gestione dalle reti autorizzate
        ip saddr @mgmt4 tcp dport 22 accept
        ip6 saddr @mgmt6 tcp dport 22 accept
        ip saddr @mgmt4 udp dport 161 accept

        # Ping con limite e margine per i burst
        ip protocol icmp icmp type echo-request limit rate 20/second burst 40 packets accept
        meta l4proto ipv6-icmp icmpv6 type echo-request limit rate 20/second burst 40 packets accept

        # Registra pochi scarti e conta il resto
        limit rate 5/minute log prefix "cp-drop: " counter drop
        counter drop
    }
}

Le regole BGP verificano l’indirizzo sorgente oltre alla porta TCP 179. La regola OSPFv3 accetta traffico da indirizzi IPv6 link-local con numero di protocollo 89. Per BFD, l’esempio consente UDP dal peer IPv4 sulle porte 3784 e 4784. Adatta queste eccezioni se la topologia usa altri protocolli o peer.

3. Convalida prima di applicare

Verifica la sintassi con nft -c -f. L’opzione -c convalida la configurazione senza applicarla. Non caricare un filtro restrittivo su un router remoto senza predisporre una modalità di ripristino: un errore nelle regole SSH può lasciarti senza accesso di gestione. L’esempio originale consiglia di provare in un laboratorio virtuale e di applicare le regole con un rollback temporizzato.

# Verifica il file senza applicare le modifiche
sudo nft -c -f router.nft

# Se la convalida non restituisce errori, carica le regole
sudo nft -f router.nft

Il caricamento di un file di regole si esegue con nft -f. Esegui il secondo comando solo dopo aver controllato gli indirizzi e i servizi consentiti e aver predisposto un modo per ripristinare l’accesso in caso di problemi.

4. Controlla i contatori e prova con traffico controllato

Dopo aver caricato la policy, elenca il ruleset e la catena specifica. I contatori aiutano a individuare quali regole ricevono traffico e se gli scarti aumentano. Il limite del ping accetta fino a 20 richieste al secondo con un burst di 40 pacchetti; le richieste che superano il limite non corrispondono a questa regola di accettazione e finiscono nello scarto finale.

# Controlla il ruleset caricato
sudo nft list ruleset

# Esamina le regole e i relativi contatori
sudo nft list chain inet cp input

Il test va eseguito da un host di laboratorio, non contro un router in produzione. Un ping -f controllato può generare richieste oltre il limite; durante il test, verifica dall’ambiente di prova che la sessione BGP sia ancora attiva. La pubblicazione da cui proviene l’esempio avverte che le regole sono state redatte sulla base della documentazione e non sono state testate su un router reale.

Errori che possono interrompere l’accesso

Non limitare il traffico di transito con questa catena: l’hook input copre solo i pacchetti consegnati al router. Per filtrare il traffico inoltrato serve una policy separata in forward.

È anche facile dimenticare che una regola di accettazione deve includere tutte le origini valide. Se il peer BGP effettivo non corrisponde ai set, la policy predefinita lo scarterà. E se gestisci il router tramite IPv6, verifica che l’indirizzo sorgente della tua postazione appartenga a mgmt6 prima di attivare il filtro.

Infine, non trattare tutti i protocolli come se fossero traffico diagnostico. La pubblicazione distingue tra routing, rilevamento, gestione ed echo: limitare in modo rigido i protocolli di routing può influire sulle sessioni, mentre il ping si presta a un limite esplicito. La gestione di BGP può inoltre essere integrata con protezioni di sessione come TCP-AO o MD5, sicurezza TTL e limiti al numero massimo di prefissi; il filtro del firewall non le sostituisce.

La policy si concentra così su una domanda specifica: quali servizi deve gestire il router, da quali origini e con quali limiti. Prima di distribuirla al di fuori del laboratorio, verifica che indirizzi, protocolli e modalità di ripristino corrispondano alla tua rete.

Fonti: DEV Community, Netfilter Project, nftables wiki