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 avviene dopo che questo hook è stato chiamato: di fatto, il codice di routing è chiamato prima (per comprendere l'indirizzo IP sorgente e alcune opzioni IP) e richiamato nuovamente se il pacchetto è stato alterato.
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 anche la priorità che essa deve avere nell'ambito dell'hook. Quando l'hook di netfilter sarà invocato dal codice del nucleo di rete, ciascun modulo registrato per questo punto sarà richiamato secondo l'ordine di priorità e sarà libero di manipolare il pacchetto. Il modulo potrà 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 della 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 (con le funzioni di ciascun hook disposte secondo l'ordine con cui sono attualmente richiamate):
--->PRE------>[ROUTE]--->FWD---------->POST------>
Conntrack | Filter ^ NAT (Src)
Mangle | | Conntrack
NAT (Dst) | [ROUTE]
(QDisc) v |
IN Filter OUT Conntrack
| Conntrack ^ 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 per l'utente molto più semplici rispetto a ipchains. 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 CONFIG_IP_NF_NAT_LOCAL è definito, gli hook NF_IP_LOCAL_OUT e NF_IP_LOCAL_IN sono utilizzabili 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 di manipolamento dei pacchetti (tabella `mangle') è utilizzata per il cambiamento delle informazioni dei pacchetti. Si "aggancia" a netfilter nei punti NF_IP_PRE_ROUTING e NF_IP_LOCAL_OUT.
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.