Le suivi de connexion est un concept essentiel dans Netfilter. C'est une sorte d'intelligence artificielle qui permet d'établir des liens de cause à effet entre les paquets qui passent dans la pile. Il faut, à un moment donné, dire quelques mots à propos de ce suivi de connexion. Comme c'est une notion qui va intervenir aussi bien dans le filtrage que dans la traduction d'adresses, autant en parler tout de suite.
Le principe du suivi de connexion permet de réaliser un « firewall statefull », c'est à dire qu'il va réagir intelligemment sur une connexion donnée, suivant son état. Voyez éventuellement à ce propos le chapitre sur la sécurité. Comme ce n'est pas très simple d'expliquer ça, nous allons observer un exemple sur le terrain. Nous allons établir une connexion TCP à partir du protocole HTTP :
No. Time Source Destination Protocol Info 10 10.181832 192.168.0.10 212.27.35.1 TCP 4252 > http [SYN] 11 10.204707 212.27.35.1 192.168.0.10 TCP http > 4252 [SYN, ACK] 12 10.204848 192.168.0.10 212.27.35.1 TCP 4252 > http [ACK] 13 10.205333 192.168.0.10 212.27.35.1 HTTP GET / HTTP/1.1
L'établissement d'une connexion TCP suit un protocole strict :
Observons également les sockets.
La même chose, mais plus détaillée, ce qui donne l'occasion de voir l'ensemble des « flags » exploitables au niveau TCP :
Frame 10 (62 bytes on wire, 62 bytes captured) ... Transmission Control Protocol Source port: 4252 (4252) Destination port: http (80) Sequence number: 3290220049 Header length: 28 bytes Flags: 0x0002 (SYN) 0... .... = Congestion Window Reduced (CWR): Not set .0.. .... = ECN-Echo: Not set ..0. .... = Urgent: Not set ...0 .... = Acknowledgment: Not set .... 0... = Push: Not set .... .0.. = Reset: Not set .... ..1. = Syn: Set .... ...0 = Fin: Not set ... Frame 11 (62 bytes on wire, 62 bytes captured) ... Transmission Control Protocol Source port: http (80) Destination port: 4252 (4252) Sequence number: 1602605975 Acknowledgement number: 3290220050 Header length: 28 bytes Flags: 0x0012 (SYN, ACK) 0... .... = Congestion Window Reduced (CWR): Not set .0.. .... = ECN-Echo: Not set ..0. .... = Urgent: Not set ...1 .... = Acknowledgment: Set .... 0... = Push: Not set .... .0.. = Reset: Not set .... ..1. = Syn: Set .... ...0 = Fin: Not set ... Frame 12 (54 bytes on wire, 54 bytes captured) ... Transmission Control Protocol Source port: 4252 (4252) Destination port: http (80) Sequence number: 3290220050 Acknowledgement number: 1602605976 Header length: 20 bytes Flags: 0x0010 (ACK) 0... .... = Congestion Window Reduced (CWR): Not set .0.. .... = ECN-Echo: Not set ..0. .... = Urgent: Not set ...1 .... = Acknowledgment: Set .... 0... = Push: Not set .... .0.. = Reset: Not set .... ..0. = Syn: Not set .... ...0 = Fin: Not set Window size: 16944 Checksum: 0xe79b (correct)
De ces premières observations, nous pouvons déduire quelques choses intéressantes. En considérant des échanges TCP entre deux sockets toujours les mêmes :
Mais voyons un peu plus loin…
No. Time Source Destination Protocol Info 29 10.427697 192.168.0.10 212.27.35.1 TCP 4252 > http [ACK] 30 10.731147 192.168.0.10 212.27.35.1 TCP span class="bhly">4253 > http span class="bhly">[SYN] 31 10.752981 212.27.35.1 192.168.0.10 TCP http > 4253 [SYN, ACK] 32 10.753165 192.168.0.10 212.27.35.1 TCP 4253 > http [ACK] 33 10.753707 192.168.0.10 212.27.35.1 HTTP GET /images/titre.gif HTTP/1.1 34 10.780941 192.168.0.10 212.27.35.1 TCP 4252 > http [FIN, ACK]
Ce que nous observons ici, c'est l'établissement d'une nouvelle connexion TCP entre les mêmes protagonistes. Bien entendu pour éviter les mélanges, le port du client n'est plus le même. C'est cette fois-ci 4253.
Autrement dit, le même client (192.168.0.10) ouvre une nouvelle connexion TCP sur le même serveur (212.27.35.1), toujours sur le port 80, mais attend les réponses sur un nouveau port, alors que la connexion précédente existe toujours.
Le client met fin à la précédente (trame 34) avec le flag [FIN] une fois seulement que la seconde connexion est établie.
Dans ces conditions, il est pertinent de penser que cette nouvelle connexion est en relation directe avec la première. Nous dirons que c'est une connexion en relation avec la première.
Si l'on met en place un système capable de mémoriser ce qu'il se passe sur la couche TCP, alors il va devenir possible de savoir si une connexion est dans l'un de ces états :
Ceci est intéressant, parce que l'on pourra interdire à priori à toute connexion NEW d'entrer dans notre installation, il n'y a aucune raison qu'il en rentre si nous n'avons pas de serveur. Eventuellement, nous pourrons par exemple créer des exceptions pour les port ssh, si nous souhaitons accéder à notre machine depuis le Net.
En revanche, toute connexion ESTABLISHED ou RELATED devra pouvoir entrer depuis le Net.
Dans l'autre sens, du LAN vers le Net, les paquets NEW doivent pouvoir passer, de même, bien entendu que les ESTABLISHED et les RELATED.
Les paquets INVALID pourront éventuellement être tracés dans les logs.
Là, c'est plus délicat puisqu'il n'y a justement pas de connexion. Il sera donc impossible de définir de façon précise l'état d'un échange UDP. Ce que l'on pourra faire, c'est mettre en place un « timer » pour décider de l'état d'un paquet UDP. Nous pouvons prendre l'exemple simple d'une requête DNS depuis notre réseau privé.
NEW
. Il déclenche un timer,ESTABLISHED
.Un module principal de suivi de connexion est chargé dynamiquement en cas de besoin, il s'agit du module ip_conntrack. Cependant tout n'est pas toujours si simple et ce module peut montrer ses limites sur des protocoles particulièrement complexes, comme par exemple FTP.
ip_conntrack ne pourra assurer qu'une connexion FTP de type passive. Si l'on souhaite assurer le suivi de connexion sur du FTP en mode actif, il faudra avoir recours au module spécialisé nf_conntrack_ftp
. Mais celui-ci ne se chargera pas dynamiquement, Nous aurons à le charger nous-même. Nous aurons aussi besoin dans ce cas de nf_nat_ftp
; si notre passerelle fait du NAT.
Nous verrons sur le terrain le travail de conntrack
dans divers exemples.