7.4. Connexions TCP

Dans cette section et les suivantes, nous examinerons plus en détail les états et comment ils sont gérés pour les trois protocoles élémentaires TCP, UDP et ICMP. Nous verrons aussi comment les états sont gérés par défaut, s'ils ne peuvent être assimilés à un quelconque de ces trois protocoles. Nous choisissons de démarrer avec le protocole TCP car c'est un protocole à état en lui-même, avec nombre de caractéristiques intéressantes en rapport avec la machine d'état d'iptables.

Une connexion TCP démarre toujours avec l'établissement d'une liaison en 3 phases, qui met en place et négocie la connexion qui servira pour le transfert des données. Toute la session commence par un paquet SYN, suivi d'un paquet SYN/ACK et se termine par un paquet ACK pour accuser réception de l'établissement de la session. A cet instant, la connexion est établie et prête à envoyer des données. La problème est le suivant : comment le traçage de connexion peut-il s'accrocher à cette étape ? En fait, très simplement.

En ce qui concerne l'utilisateur, le traçage de connexion fonctionne de façon identique pour tout type de connexion. Observez le schéma ci-dessous pour comprendre dans quel état se trouve le flux aux différentes étapes de la connexion. Comme vous le voyez, le code du traçage de connexion ne suit pas vraiment les étapes de la connexion TCP du point de vue de l'utilisateur. Dès qu'un paquet SYN arrive, il considère la connexion comme nouvelle (NEW). Dès qu'un paquet de réponse SYN/ACK est observé, il considère la connexion comme établie (ESTABLISHED). Si vous réfléchissez une seconde, vous comprendrez pourquoi. Avec cette implémentation particulière, vous pouvez autoriser des paquets NEW et ESTABLISHED à quitter votre réseau local, et autoriser seulement des connexions ESTABLISHED en retour, et ça fonctionnera sans problème. A contrario, si la machine de traçage de connexion considérait l'établissement complet de la connexion comme NEW, il serait impossible d'arrêter les connexions issues de l'extérieur vers le réseau local, puisqu'il faudrait à nouveau autoriser le retour de paquets NEW. Pour rendre les choses encore plus compliquées, il existe de nombreux autres états internes qui sont utilisés pour les connexions TCP à l'intérieur du noyau, mais qui ne sont pas disponibles dans l'espace utilisateur. Brièvement, ils respectent les états standards spécifiés dans la RFC 793 - Transmission Control Protocol aux pages 21-23.

Comme vous pouvez le voir, c'est tout à fait simple, du point de vue de l'utilisateur. Cependant, en regardant la construction complète du point de vue du noyau, c'est un peu plus compliqué. Voyons un exemple. Regardons exactement comment les états de connexion changent dans la table /proc/net/ip_conntrack. Le premier état est rapporté sur le reçu d'un premier paquet SYN dans la connexion.

tcp      6 117 SYN_SENT src=192.168.1.5 dst=192.168.1.35 sport=1031 \
     dport=23 [UNREPLIED] src=192.168.1.35 dst=192.168.1.5 sport=23 \
     dport=1031 use=1

Comme nous l'indique l'entrée ci-dessus, nous avons un état précis dans lequel un paquet SYN a été envoyé, (le drapeau SYN_SENT est placé), et pour lequel aucune réponse n'a été envoyée (en témoigne le drapeau [UNREPLIED]). L'état interne suivant sera joint quand nous verrons un autre paquet dans l'autre direction.

tcp      6 57 SYN_RECV src=192.168.1.5 dst=192.168.1.35 sport=1031 \
     dport=23 src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 \
     use=1

Maintenant nous avons reçu un SYN/ACK correspondant en retour. Dès que ce paquet a été reçu, l'état change encore une fois, cette fois vers SYN_RECV. SYN_RECV nous indique que le SYN d'origine a été délivré correctement et que le SYN/ACK en retour passe aussi à travers le pare-feu proprement. D'ailleurs, cette entrée de traçage de connexion a observé le trafic dans les deux directions et considère désormais qu'il y a été répondu. Ceci n'est pas explicite, mais nous assumons, comme l'était le fanion [UNREPLIED] ci-dessus. L'étape finale sera atteinte lorsque nous aurons vu le ACK dans l'établissement d'une liaison à trois voies.

tcp      6 431999 ESTABLISHED src=192.168.1.5 dst=192.168.1.35 \
     sport=1031 dport=23 src=192.168.1.35 dst=192.168.1.5 \
     sport=23 dport=1031 [ASSURED] use=1

Dans le dernier exemple, nous avons obtenu le ACK final dans l'établissement d'une liaison à trois voies et la connexion a pris l'état ESTABLISHED, pour autant que les mécanismes internes de Iptables soient avisés. Normalement, le flux de données sera ASSURED maintenant.

Une connexion peut aussi être dans l'état ESTABLISHED, mais pas [ASSURED]. Ceci survient lorsque nous avons une connexion captée ouverte (nécessite le patch tcp-window-tracking et le ip_conntrack_tcp_loose placé à 1 ou plus haut). Par défaut, sans le patch tcp-window-tracking, c'est ce comportement qui s'applique, et il n'est pas modifiable.

Quand une connexion TCP est close, elle est faite de cette façon et prend les états suivants.

Comme vous pouvez le voir, la connexion n'est jamais réellement fermée jusqu'à ce que le ACK soit envoyé. Notez que cette figure décrit simplement comment elle est fermée dans des circonstances normales. Une connexion peut aussi, par exemple, être fermée par l'envoi d'un RST (reset), si celle-ci a été refusée. Dans ce cas, la connexion sera fermée immédiatement.

Quand la connexion TCP a été fermée, elle entre dans l'état TIME_WAIT, qui est, par défaut, de 2 minutes. Ceci est utilisé pour que tous les paquets sortants puissent encore passer à travers notre table de règles, même après que la connexion soit fermée. Ceci est employé comme une sorte de tampon pour que les paquets qui ont été immobilisés dans un ou plusieurs routeurs engorgés puissent encore passer le pare-feu, ou vers une autre fin de connexion.

Si la connexion est réinitialisée par un paquet RST, l'état est modifié en CLOSE. Ce qui indique que la connexion a, par défaut, 10 secondes avant que la connexion complète soit fermée définitivement. Les paquets RST ne sont pas reconnus dans aucun sens, et couperont la connexion directement. Il existe aussi d'autres états que ceux dont nous avons parlé. Voici une liste complète des états qu'un flux TCP peut prendre, et leurs valeurs de délai d'attente.

Tableau 7.2. États internes

État Délai
NONE 30 minutes
ESTABLISHED 5 jours
SYN_SENT 2 minutes
SYN_RECV 60 secondes
FIN_WAIT 2 minutes
TIME_WAIT 2 minutes
CLOSE 10 secondes
CLOSE_WAIT 12 heures
LAST_ACK 30 secondes
LISTEN 2 minutes

Ces valeurs ne sont pas absolues. Elles peuvent changer en fonction des versions du noyau, et également par le système de fichiers dans les variables /proc/sys/net/ipv4/netfilter/ip_ct_tcp_*. Les valeurs par défaut seront, cependant, justes en pratique. Ces valeurs sont établies en secondes.

[Note] Note

Notez aussi que le domaine utilisateur de la machine d'état ne doit pas voir les fanions TCP (i.e., RST, ACK et SYN sont des fanions) placés dans les paquets TCP. Ce n'est généralement pas recommandé, car vous pourriez autoriser les paquets dans l'état NEW à traverser le pare-feu, mais quand vous spécifiez le fanion NEW, vous indiquez les paquets SYN.

Ce n'est pas ce qui se produit avec l'implémentation de l'état; ce qui veut dire, même un paquet avec aucun bit de placé ou un fanion ACK, sera compté comme NEW. Ceci peut être utilisé pour faire de la redondance de pare-feu, mais c'est en général très déconseillé pour un réseau domestique, dans lequel vous avez un seul pare-feu. Pour en savoir plus vous pouvez utiliser la commande expliquée dans la section Section B.2, « Paquets NEW non-SYN » de l'annexe Annexe B, Problèmes et questions courants. Un autre moyen est d'installer l'extension tcp-window-tracking depuis patch-o-matic, et de placer /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_loose à zéro, le pare-feu effacera tous les paquets NEW en ayant le fanion SYN placé.