Netfilter est pratiquement une série de ``hooks'' (accroches) à
quelques endroits dans la pile de protocoles (pour le moment, IPv4,
IPv6, DECnet). Le shema de traversé ressemble (idéalement) à
cela:
Un paquet qui traverse le système Netfilter:
--->[1]--->[ROUTE]--->[3]--->[4]--->
| ^
| |
| [ROUTE]
v |
[2] [5]
| ^
| |
v |
Sur la gauche, c'est la ou les paquets arrivent : en ayant passé
un simple test de sanité (par exemple: pas coupé, IP checksum est
OK, et que ce n'est pas un paquet reçu en promiscuous), ils sont
passés au ``hook'' NF_IP_PRE_ROUTING [1] du canevas de
netfilter.
Ensuite, il entrent dans le code de routage, qui décide si oui
ou non le paquet est destiné à une autre interface, ou pour un
processus en local. Le code de routage peut éventuellement détruire
le paquet si il n'est pas routable.
Si il est destine pour la machine elle même, le canevas
netfilter est appelé pour le hook NF_IP_LOCAL_IN [2], avant d'être
passé au processus, si il y en a un.
Si à la place le paquet est destiné pour une autre interface, le
canevas netfilter est appelé pour le hook NF_IP_FORWARD [3].
Le paquet passe ensuite le dernier hook de netfilter, le
NF_POST_ROUTING [4], avant d'être envoyé sur le cable.
Le hook NF_IP_LOCAL_OUT [5] est appelé pour les paquets qui sont
générés localement. Ici vous pouvez voir que le routage ce fait
après que ce hook est appelé : en fait, le code de routage est
appelé avant (pour trouver l'adresse source IP, et quelques options
IP) : si vous voulez modifier le routage, vous devez modifier le
champs `skb->dst' par vous même, comme dans le code de NAT.
Maintenant nous avons un exemple de netfilter pour IPv4, vous
pouvez voir quand chacun des hooks est activé. C'est l'essence même
de netfilter.
Les modules kernel peuvent s'enregistrer pour écouter à chacun
de ces hooks. Un module qui enregistre une fonction doit spécifier
la priorité de cette fonctions à l'intérieur du hook. De telle
sorte que quand ce hook est appelé par netfilter, le code réseaux
central appellera les fonctions du hook dans l'ordre des priorités.
Le module peut dire à netfilter de faire l'une de ces 5 choses
:
NF_ACCEPT: le paquet peut continuer sa traversé comme
normal.
NF_DROP: détruit le paquet, la traversé est arrêtée net.
NF_STOLEN: J'ai pris possession du paquet, arrête la
traversée.
NF_QUEUE: queute le paquet (habituellement pour manipulation
future en userspace).
NF_REPEAT: Appelle ce hook encore une fois.
Les autres parties de Netfilter (gérer les paquets queutés, et
les commentaires cools) seront couverts dans la section kernel un
peu plus tard.
Basé sur cette fondation, nous pouvons construire des
manipulations de paquets relativement complexes, comme démontré
dans les deux sections suivantes.
Un système de sélection de paquets appelé `iptables' a été
construit par dessus le canevas netfilter. C'est le descendant
direct de `ipchains' (qui descendait de `ipfwadm', qui venait lui
même de ipfw de BSD) mais amélioré car plus extensible. Les modules
kernels peuvent demander à enregistrer une table nouvelle, et
demander à ce qu'un paquet traverse un table donnée. Cette méthode
de sélection de paquets est utilisée pour filtrer les paquets (la
table `filter'), pour NAT (la table `nat') et pour modifier des
paquets avant routage (la table `mangle').
Les hooks qui sont enregistrés avec netfilter sont comme suit
(avec les fonctions de chaque hooks dans l'ordre ou ils sont
appelles) :
--->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
Filtrage de paquets
Cette table, `filter', ne devrait jamais modifier les paquets :
seulement les filtrer.
Un des avantages des filtres de iptables comparés à ceux de
ipchains est que c'est petit et rapide, et que ça s'accroche dans
netfilter aux points NF_IP_LOCAL_IN, NF_IP_FORWARD, et
NF_IP_LOCAL_OUT. Ça veut dire que pour un paquet donné, il n'y a
qu'une et un seule place pour le filtrer. Cela rend les choses bien
plus simples pour l'utilisateur que ipchains ne l'était. Aussi, le
fait que le canevas netfilter fournit l'interface input et output
pour les hooks NF_IP_FORWARD signifie que beaucoup de types de
filtrage sont rendus plus simples.
Note: J'ai porté les parties kernel de ipchains et de ipfwadm en
modules par dessus le canevas netfilter. Cela permet l'usage des
vieux utilitaires en userspace ipfwadm et ipchains, sans avoir à
mettre à jour.
NAT
Voici la réaction de la table `nat', à qui l'on passe des
paquets par deux hooks netfilter : pour les paquets qui ne sont pas
générés localement, les hooks NF_IP_PRE_ROUTING et
NF_IP_POST_ROUTING sont une place parfaite pour modifier
respectivement la destination et la source d'un paquet. Si
CONFIG_IP_NF_NAT_LOCAL est définie, le hook NF_IP_LOCAL_IN est
utilisé pour modifier la destination des paquets générés
localement.
Cette table est légèrement différente de la table `filter',
effectivement, seulement le premier paquet d'une nouvelle connexion
va traverser la table : le résultat de cette traversé est ensuite
appliquée à tous les futurs paquets qui font partie de la même
connexion.
Masquerading, Port Forwarding, et Proxy transparent
Je divise NAT en Source NAT (ou le premier paquet voit sa source
être modifiée) et Destination NAT (ou le premier paquet voit sa
destination être modifiée).
Le Masquerading est une forme spéciale de Source NAT,
port-forwarding et transparent proxying sont des formes spéciales
de Destination NAT. Elles sont toutes maintenant effectuées à
l'aide du canevas NAT, plutôt que d'être des entités
indépendantes.
Modification de Paquets
La table de modification de paquets (la table `mangle') est
utilisée pour des changements concrets des informations d'un
paquet. Les exemples sont la target TOS et la target TCPMSS. La
table mangle s'accroche aux 3 hooks de netfilter (veuillez noter
que ceci a changé à partir du noyau 2.4.18. Les noyaux précédents
n'avaient pas la table mangle accrochée à tout les hooks).
Le suivi des connexions est fondamental pour NAT, mais il est
implémenté dans un module à part entière. Cela permet une extension
au code de filtrage de paquets pour simplement et proprement
implémenter le suivi de connexions (le module `state').
Cette nouvelle flexibilité fournit une opportunité de faire des
choses vraiment cools, et de manière plus importante permet aux
gens d'écrire des améliorations ou des remplacement complets.