Netfilter et IPtables
09/02/2005
 Christian CALECA 
Liste des cours

Conntrack

Accueil ] [ Architecture ] [ Conntrack ] [ Filter ] [ NAT ] [ Et le reste ] [ iptables ]


Le suivi de connexion

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.

Expérience préliminaire

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      4253 > http [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.

Premières déductions

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.

Et pour l'UDP ?

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é.

Dans la pratique

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é ip_conntrack_ftp. Mais celui-ci ne se chargera pas dynamiquement, vous aurez à le charger vous-même. Nous aurons aussi besoin dans ce cas de ip_nat_ftp; si notre passerelle fait du NAT.

Nous verrons sur le terrain le travail de conntrack dans divers exemples.

 


Précédente ] [ Accueil ] [ Suivante ]