nftables

uno strumento per filtrare i pacchetti

presentazioni

Quello che vediamo è un modo per gestire il traffico di rete, a meno della sintassi utilizzata e dal particolare strumento la stessa cosa può essere fatta con qualsiasi firewall.

nftables è il nuovo sistema di filtraggio dei pacchetti per il kernel di Linux, dovrebbe sostituire il vecchio (ma attualmente molto usato) iptables.

Va però rilevato che il sistema è più nuovo rispetto ad iptables (gli autori sono sempre gli stessi) e che la documentazione non è ancora... sovrabbondante... le informazioni fanno riferimento a nftables>0.8 e un kernel linux>3.18

Il pacchetto da installare è nftables e l'inoltro dei pacchetti (forwarding) del kernel deve essere ovviamente abilitato.

strutture generali

In linea di principio il funzionamento del sistema si basa su delle tabelle che contengono delle catene che a loro volta contengono regole. Per interagire con il sistema (che fa parte del kernel) si usa il comando nft.

table
è la tabella e va associata ad un protocollo come ad esempio ipV4 o ipV6, la regola successiva crea una tabella per lavorare su ipV4
nft add table ip tEsempio
chain
è una catena in cui verranno inserite le regole, ogni catena ha un punto di aggancio nel sistema di instradamento del kernel:
programming java
i punti di aggancio sono i rettangoli nel diagramma, in giallo sono evidenziati quelli che attraversano il server. Ogni catena ha una priorità (perché catene di tabelle diverse vengono valutate in base alla loro priorità) e una politica di default che è accept o drop. nft add chain ip tEsempio cEsempio { type filter hook prerouting priority 0 \; policy accept \; }
Parafrasi: aggiungi una catena chiamata cEsempio alla tabella chiamata tEsempio che processa traffico ipV4, questa catena è un filtro che va agganciato nel punto chiamato prerouting, come comportamento predefinito accetta i paccetti.
rule
sono le regole che decidono le sorti dei pacchetti: specificano una regola per selezionare i pacchetti e un verdetto per i pacchetti che combaciano con la regola (es: butta tutti i pacchetti che arrivano dall'hosto 10.1.2.3).

gestione delle tabelle

I comandi per la gestione delle tabelle sono piuttosto sempici, ne vediamo un breve elenco (nel quale tutte le tabelle iniziano con "t" soltanto per evidenziarne il nome).

nft add table ip tNAT
aggiunge la tabella tNAT che lavora su ip
nft delete table ip tNAT
elimina la tabella
nft list tables
visualizza un elenco di tutte le tabelle presenti nel sistema
nft list table ip tNAT
mostra il contenuto della tabella tNAT
nft list ruleset
mostra tutte le regole

In generale "ip" può essere omesso perché viene assunto come valore predefinito.

NAT/masquerading

Vediamo per primo il percorso più semplice, ma lo vediamo in 3 modi diversi!

Negli esempi usiamo 10.0.1.0/24 come rete interna su cui vogliamo fare Network Address Translation (o Masquerading che dir si voglia) e 10.0.0.2 come IP della nostra macchina verso la rete esterna.

Comandi diretti

Scriviamo uno per uno i comandi:

# nft add table tMascheramento
# nft add chain tMascheramento cIngresso { type nat hook prerouting priority 0 \; }
# nft add chain tMascheramento cUscita { type nat hook postrouting priority 100 \; }
# nft add rule tMascheramento cUscita ip saddr 10.0.1.0/24 oif enp2s11 masquerade

La regola asserisce: "tutto il traffico che viene dalla rete 10.0.1.0/24 e va verso l'interfaccia enp2s11 va mascherato".

Attenzione ad un paio di cose: la catena agganciata al punto di prerouting serve (anche se è vuota) per i pacchetti di ritorno, il "\" prima del ";" serve soltanto per evitare che la shell (Bash o chi per lui) interpreti il punto e virgola.

Uno script per nft

Scrivere il seguente codice in un file e renderlo eseguibile. La prima riga indica che ad interpretare il file deve essere il solito comando... nft!

#!/usr/sbin/nft -f
add table tMascheramento
add chain tMascheramento cIngresso { type nat hook prerouting priority 0 ; }
add chain tMascheramento cUscita { type nat hook postrouting priority 100 ; }
add rule tMascheramento cUscita ip saddr 10.0.1.0/24 oif enp2s11 masquerade

Altro script per nft

Stesso discorso di sopra ma con una sintassi diversa (quella ottenuta in output da nft list ruleset)

#!/usr/sbin/nft -f
table ip tMascheramento {
        chain cIngresso {
                type nat hook prerouting priority 0; policy accept;
        }

        chain cUscita {
                type nat hook postrouting priority 100; policy accept;
                nftrace set 1 ip saddr 10.0.1.0/24 oif "enp2s11" masquerade
        }
}

alternativa

Anzichè usare "masquerade" è possibile usare una sintassi diversa... che fa però lo stesso lavoro: snat indirizzo_IP e al posto di indirizzo_IP va inserito l'IP che deve essere inserito nel pacchetto in uscita, cioè quello dell'interfaccia che usiamo per uscire: 10.0.0.2 nel nostro caso.

Firewall

In linea di principio non è difficile a questo punto scartare i pacchetti, poniamo di avere una tabella chiamata tFuoco con una catena chiamata cInoltro agganciata su forward.

Come si crea la catena cInoltro?

nft add chain cInoltro { type filter hook forward priority 100 \; }non hai inserito il nome della tabella nft add chain tFuoco cInoltro { type filter hook prerouting priority 100 \; }il punto di aggancio è sbagliato nft add chain tFuoco cInoltro { type filter hook forward priority 100 \; } nft add chain tFuoco cInoltro non hai specificato la configurazioen della catena

Se ad esempio voglio scartare tutti i pacchetti che vanno verso uno dei DNS di Google posso scrivere:
nft add rule tFuoco cInoltro ip daddr 8.8.8.8 drop

Port forwarding

Se un server funge da punto di accesso ad una rete potrebbe capitare che deve inoltrare alcune richieste verso altre macchine che non sono connesse ad internet con un IP pubblico: questo meccanismo si chiama "forwarding". Capita ad esempio quando il server web non è direttamente connesso alla rete esterna.

Siccome queste regole (una sola per ogni server!) sono di tipo NAT potrebbe essere una buona idea inserirle nella tabella che fa già NAT (se la abbiamo ovviamente).

Il caso più semplice è questo: le richieste che mi arrivano sulla porta 80 devo girarle al server il cui indirizzo è a.b.c.d la regola è la seguente:
nft add rule tTabella cCatena iif enp2s11 tcp dport 80 dnat a.b.c.d
oppure con una sintassi alternativa:
nft add rule tTabella cCatena dnat tcp dport map { 80 : a.b.c.d }

Esiste però la possibilità che le richieste che mi arrivano su una porta io debba instradarle verso un'altra macchina e un'altra porta, possibile anche questo:
nft add rule tNomeTabella cNomeCatena iif enp2s11 dnat tcp dport map { 8080 : 10.0.1.2 } : tcp dport map { 8080 : 80 }
parafrasi: tutto il traffico che arriva dall'interfaccia enp2s11 sulla porta 8080 devi inoltrarlo verso la macchina 10.0.1.2 porta 80.

In caso possa servire posso redirigere più porte verso macchine diverse con un unico comando: nft add rule tNomeTabella cNomeCatena dnat tcp dport map { 8888 : 10.0.1.2, 9999: 10.0.1.3} : tcp dport map { 8888 : 80, 9999: 8080 }

debug

Purtroppo le cose non vanno sempre bene! Fortunatamente abbiamo degli strumenti per tracciare cosa succede.

Basta inserire meta nftrace set 1 in una regola prima del verdetto (accept o simile) come ad esempio in
nft add rule tMascheramento cUscita meta nftrace set 1 ip saddr 10.0.1.0/24 oif enp2s11 masquerade
oppure inserendo una regola come la seguente all'inizio di una catena
nft add rule tMascheramento cUscita meta nftrace set 1

Fatto questo il comando nft monitor trace ci permetterà di vedere cosa succede al traffico che attraversa il sistema.

Bibliografia

nftables wiki