Netfilter consiste semplicemente in una serie di hook collocati in vari punti del protocol stack (in questo momento, IPv4, IPv6 e DECnet). Il diagramma (idealizzato) di attraversamento nel caso dell'IPv4 assomiglia al seguente:
Pacchetto che attraversa il sistema Netfilter:
--->[1]--->[Instradamento]--->[3]--->[4]--->
| ^
| |
| [Instradamento]
v |
[2] [5]
| ^
| |
v |
I pacchetti arrivano sulla sinistra: dopo aver passato il semplice controllo di sanità (ossia, no troncature, IP checksum OK, ricezione non confusa) sono passati all'hook NF_IP_PRE_ROUTING [1] del framework netfilter.
Successivamente entrano nel codice di routing, il quale decide se il pacchetto è destinato ad un'altra interfaccia o ad un processo locale. Il codice di routing potrebbe scartare i pacchetti non instradabili.
Se è destinato alla box stessa, il framework netfilter, prima che il pacchetto sia passato al processo (se presente), è chiamato nuovamente per l'hook NF_IP_LOCAL_IN [2].
Se è invece destinato ad un'altra interfaccia il framework netfilter è chiamato per l'hook NF_IP_FORWARD [3].
Il pacchetto poi, prima di essere immesso nuovamente nel cavo, passa all'hook finale, l'hook NF_IP_POST_ROUTING [4].
L'hook NF_IP_LOCAL_OUT [5] è chiamato per i pacchetti creati localmente. Si può qui notare che il codice di routing viene eseguito dopo che questo hook è stato chiamato: di fatto, il codice di routing è chiamato prima (per comprendere l'indirizzo IP sorgente e alcune opzioni IP): se si vuole alterare il routing bisogna modificare il campo `skb->dst', come è fatto nel codice che gestisce il NAT.
Ora segue un esempio riguardante netfilter per IPv4, si potrà notare quando ciascun hook è attivato. Questa è l'essenza di netfilter.
I moduli del kernel possono registrarsi per "ascoltare" qualsiasi hook. Un modulo che registra una funzione deve specificare la sua priorità all'interno dell'hook. Quando poi l'hook di netfilter è invocato dal codice del nucleo di rete, ciascun modulo registrato per questo punto è chiamato seguendo l'ordine definito dalle priorità, ed è libero di manipolare il pacchetto. Il modulo può inoltre specificare a netfilter di effettuare una delle seguenti cinque cose:
Le altre parti di netfilter (gestione dei pacchetti accodati, commenti) saranno trattate più avanti nella sezione riguardante il kernel.
Subito dopo questi concetti base, si possono realizzare complesse manipolazioni dei pacchetti, come descritto nei prossimi due paragrafi.
Un sistema di selezione dei pacchetti, denominato IP Tables, è stato realizzato al di sopra del framework netfilter. E' un diretto discendente di ipchains (che proviene da ipfwadm, che a sua volta deriva da ipfw IIRC dei sistemi BSD) con in più l'estendibilità. I moduli del kernel possono registrare una nuova tabella e richiedere che un determinato pacchetto attraversi la tabella indicata. Questo metodo di selezione dei pacchetti è utilizzato per il filtraggio dei pacchetti (tabella `filter'), per il Network Address Translation (tabella `nat'), e per il manipolamento generico dei pacchetti prima dell'instradamento (tabella `mangle').
Gli hook registrati con netfilter sono i seguenti (in figura sono indicate in ordine, per ogni hook, le funzioni chiamate):
--->PRE------>[ROUTE]--->FWD---------->POST------>
Conntrack | Mangle ^ Mangle
Mangle | Filter | NAT (Src)
NAT (Dst) | | Conntrack
(QDisc) | [ROUTE]
v |
IN Filter OUT Conntrack
| Conntrack ^ Mangle
| Mangle | NAT (Dst)
v | Filter
Questa tabella, `filter', non deve mai alterare i pacchetti: solo filtrarli.
Uno dei vantaggi del filtro iptables rispetto a ipchains consiste nel fatto che è più compatto e veloce, inoltre si aggancia in netfilter nei punti NF_IP_LOCAL_IN, NF_IP_FORWARD e NF_IP_LOCAL_OUT. Ciò significa che per ogni pacchetto c'è un (e solo un) punto possibile per il filtraggio. Le cose in questo modo sono molto più semplici. Inoltre, il framework netfilter provvede sia un'interfaccia di input che di output per l'hook NF_IP_FORWARD, ciò implica la possibilità di avere diversi tipi, e anche piuttosto semplici, di filtraggio.
Nota: ho implementato le porzione del kernel riguardanti ipchains e ipfwadm come moduli sopra netfilter, consentendo così di poter utilizzare i vecchi tool userspace ipfwadm e ipchains senza la necessità di un aggiornamento.
Questo è il regno della tabella `nat', che riceve i pacchetti da due hook di netfilter: per i pacchetti non locali NF_IP_PRE_ROUTING e NF_IP_POST_ROUTING sono perfetti per la modifica rispettivamente della destinazione e della sorgente. Se è definito CONFIG_IP_NF_NAT_LOCAL, gli hook NF_IP_LOCAL_OUT e NF_IP_LOCAL_IN sono usati per alterare la destinazione dei pacchetti locali.
Questa tabella è leggermente differente rispetto alla tabella `filter', in questa solo il primo pacchetto di una nuova connessione attraversa la tabella: il risultato di questa traversata sarà poi applicata a tutti i pacchetti futuri appartenenti alla stessa connessione.
Ho suddiviso il NAT in Source NAT (dove al primo pacchetto viene alterata la sorgente) e Destination NAT (al primo pacchetto viene alterata la destinazione).
Il mascheramento è una forma speciale di Source NAT: port forwarding e il proxy trasparente sono invece forme speciali di Destination NAT. Queste ora utilizzano tutte il framework NAT, invece di essere entità indipendenti.
La tabella per il packet mangling (tabella `mangle') è usata per modificare le informazioni del pacchetto.I target TOS e TCPMSS sono un esempio di utilizzo. La tabella mangle si aggancia a tutti e cinque gli hook di netfilter. (questo cambiamento è avvenuto con la versione 2.4.18 del kernel. Nei precedenti kernel mangle non si agganciava a tutti gli hook.)
Il Connection tracking (tracciamento delle connessioni) è fondamentale per il NAT, tuttavia è implementato come modulo; ciò per consentire di estendere il codice di filtraggio dei pacchetti, permettendo l'utilizzo semplice e pulito del connection tracking (modulo `state').
La nuova flessibilità fornisce l'opportunità di realizzare cose davvero incredibili, oltre che di apportare miglioramenti o di realizzare completi rimpiazzi da combinare e adattare.