Etude de différents protocoles dans un cas concret
Cette partie va entrer dans le vif du sujet, à savoir l’analyse du fonctionnement de différents protocoles entre eux. De la couche la plus basse, nous allons remonter aux protocoles applicatifs. Le but de cet exercice, est d’observer comment peut-on se connecter par le protocole applicatif telnet depuis notre machine cliente sur notre machine serveur. Ces deux machines ignorent tout de leur homologue, et vont devoir communiquer entre elles. Les seuls indices que nous avons sont : l’adresse IP du serveur (192.168.1.1), notre adresse IP (192.168.1.10) et le port sur lequel joindre notre serveur (23 pour telnet).
A. Commençons par vérifier la présence de notre serveur sur notre réseau
Pour observer si la connexion est correctement établie entre nos deux machines, nous pingons le serveur. Nous entrons dans une ligne de commande : ‘ping 192.168.1.1’. Nous obtenons une perte de 0% (voir le détail de cette commande dans la partie précédente) ; les deux machines sont à priori correctement connectées. Comme expliqué précédemment, la commande ping envoie un paquet ICMP Echo Request à la machine qu l’on ping. Il attend une réponse ICMP Echo Reply pour vérifier la connexion. Comme ici, la connexion est correctement, nous capturons le premier échange de la commande Windows qui en standard comporte quatre requêtes. Voici les deux paquets capturés :
Examinons plus en détail ces paquets :
Ø Premier paquet :
Les couches Ethernet et IP sont normales, nous remarquons dans le champ Protocol de IP, la valeur ICMP, pour passer à la bonne couche de niveau supérieur. Les paramètres de la couche ICMP sont très simples, on remarque qu’ici, le paquet envoyé est bien un Type 8 : request. Le serveur reçoit ce paquet. Puis il envoie sa réponse : ICMP Echo Reply :
Ici, la réponse ce fait correctement avec un paquet ICMP Type 0 : Reply. Le fonctionnement de la commande ping et donc du protocole ICMP est donc assez simple.
Nous venons de pinger le serveur, mais pendant ce temps là c’est passé quelque chose de très intéressant. Vous l’aurez sans doute remarqué, la commande ping a joint le serveur par son adresse IP, or cette adresse IP n’a de signification que pour la couche Internet. Comment à un niveau inférieur, notre pile TCP/IP a-t-elle pu joindre le serveur ? Tout simplement grâce au protocole ARP. A partir de l’adresse IP, il nous faut l’adresse MAC du serveur, pour que notre machine puisse envoyer les données à la carte réseau du serveur ; autrement dit, pour que les couches accès réseau sachent à qui envoyer les datagrammes d’un sens comme dans l’autre.
Une demande de correspondance par ARP correspond est effectuée en deux envois de paquets. Le premier est la demande d’adresse, et le second est la réponse contenant la correspondance désirée. Voyons rapidement les deux paquets capturés avec notre sniffer :
La machine mattieu est le client d’adresse 192.168.1.10.
Observons maintenant les paquets en détail :
Ø Premier paquet :
Constitution du paquet :
Intéressons nous d’abord à la partie Ethernet. Nous constatons que notre machine a bien envoyé à destination du broadcast physique le paquet ARP (rappelons que le broadcast physique est destiné à joindre toutes les machines du réseau local). Maintenant, regardons la partie Adress Resolution Protocol. Le datagramme est du type Request (question). Nous voyons que dans les champs Sender MAC et Sender IP nous avons mis respectivement notre adresse MAC et notre adresse IP. Dans le champ Target MAC il n’y a rien, puisque c’est ce que nous voulons savoir ;-) . Le champ Target IP correspond à l’adresse IP de notre serveur dont nous voulons connaître l’adresse MAC.
Une fois que ce datagramme est sur le réseau (les ordinateurs connectés écoutant en permanence le broadcast physique pour entre autre les demandes de correspondances), la machine ayant comme adresse IP 192.168.1.1 (le serveur) va intercepter le datagramme et va voir que la machine 192.168.1.10 veut l’adresse MAC de sa carte réseau.
Le serveur va alors répondre au client avec ce second paquet :
Constitution du paquet :
Comme d’après notre précédent paquet, le serveur connaît nos adresses MAC et IP (les champs Sender du 1er paquet), il va alors répondre non pas par broadcast physique (qui consomme énormément de bande passante) mais directement avec l’adresse MAC du client placée en adresse de destination dans l’en-tête Ethernet (ici 00 :50 :fc :1b :69 :b9). Le datagramme de réponse sera du type ARP reply (réponse), et les champs Sender et Target de l’en-tête ARP seront remplis avec les valeurs valides.
Lorsque le client va recevoir ce datagramme, il va observer le champ Sender MAC qui correspond à l’adresse MAC du serveur : ce que nous voulons savoir.
près ces deux envois, l’adresse MAC du serveur est connue par la machine cliente. On peut voir alors une entrée supplémentaire dans la table ARP de notre client. Voici une production de la commande ‘arp –a’ qui retourne la table :
Nous constatons que la correspondance a été ajoutée automatiquement (dynamique) lors du ping sur le serveur.
Nous possédons maintenant l’adresse ARP de la carte réseau à laquelle nous souhaitons nous connecter. Une connexion au serveur peut donc être envisagée. Les services telnet n’acceptent une connexion qu’en mode connecté, c'est-à-dire avec le protocole TCP. Nous allons alors suivre les différentes étapes de cette connexion. Pour se connecter au serveur par telnet, nous entrons dans une ligne de commande Windows : ‘telnet 192.168.1.1’. Notre sniffer capture tout.
Tout d’abord, revoyons les différentes étapes de la connexion par TCP. Premièrement, nous demandons si nous pouvons nous connecter au serveur. Celui-ci répond en acceptant notre demande, et demande à son tour s’il peut se connecter à nous. Nous acceptons sa demande et la connexion est établie. Voici un résumé du processus :
Ø Observons la demande de connexion :
Les en-têtes Ethernet et IP sont correctement remplis avec les adresses source et destination correspondantes. Le client commence par envoyer dans ce paquet TCP un flag SYN activé (bit mis à 1), pour faire sa demande de connection. Il définit également ses paramètres tels que le port de destination (23 pour telnet) ainsi que le port source (c’est-à-dire le port sur lequel nous acceptons que le serveur nous joigne : ici 3405). Notons que le client a une window size de 4288 octets (mémoire utilisée pour gérer le flux de la connexion). Il est aussi important de remarquer l’ISN (Initial Sequence Number) de la connection. Comme le paquet envoyé est le premier de la connection, il contient l’ISN du client. Cet ISN vaut ici 2168761095. Dans ce premier paquet, il n’y a aucune donnée.
Ø Une fois que le serveur reçoit ce paquet, il voit que le client veut se connecter sur son port 23. Comme un service telnet tourne dessus, il va accepter la demande. Et aussi faire sa demande de connection sur le port 3405 du client. Le deuxième paquet que nous relevons à l’aide du sniffer est donc le suivant :
Ce paquet à destination du port 3405 du client comporte le flag ACK (acceptant la demande de connexion formulée par le premier paquet), ainsi que le numéro d’acquittement (Acknowledgement number), permettant de valider la réception du paquet précédent. Ce numéro est ici l’ISN du client incrémenté de 1 : 2168761096. Pour faire sa demande de connexion, le serveur met dans ce même paquet le flag SYN, ainsi que son propre ISN : 2430281984. Nous pouvons constater que le serveur a une window size beaucoup plus grande que le client : 17316 octets (normal, puisque c’est un serveur ;-) ).
Ø Le client reçoit ce paquet, et n’a plus qu’à accepter la demande de connexion du serveur pour que la connexion soit établie. C’est ce qu’il fait dans un dernier paquet :
Ce paquet est envoyé au serveur sur son port 23. Il porte le numéro de séquence du paquet précédent qu’il a envoyé, incrémenté de 1 : 2168761096. Pour accepter la connexion, le flag ACK est positionné, et le numéro d’acquittement est l’ISN du serveur incrémenté de 1 : 2430281985. A partir de ce moment, la connexion est établie.
Maintenant que la connexion est établie, le protocole telnet va à son tours négocier les paramètres de connection de l’utilisateur (comme son login et mot de passe). La capture de connexion suivante permet d’observer les paquets échangés lors de la communication telnet.
Après cet échange, nous pouvons observer cet écran qui a remplacé la ligne de commande Windows : c’est l’invite de connection telnet qui a été envoyé par le serveur dans les paquets ci-dessus :
Cette capture est très intéressante, car elle permet de suivre le mécanisme de l’acquittement du protocole TCP. Il se passe des échanges de données entre les deux machines. Puis, une fois que le buffer (mémoire de la taille du window size) est complet, un acquittement (paquet ACK) est envoyé. Ces acquittements sont visibles dans la capture. Ils sont envoyés par l’un ou l’autre, selon les paramètres de configuration échangés, puisque cet échantillon concerne la mise au point de la communication telnet.
Une fois que nous obtenons le prompt ci-dessus, nous nous déconnectons du serveur grâce à la combinaison de touche <Ctrl + C>. Ceci permet de mettre fin « proprement » à la connection TCP. Une fin de connection est comme nous l’avons étudié en partie théorique se déroule en quatre étapes : une annonce de fin de connexion d’une machine, l’acquittement de l’autre, l’annonce de fin de connexion de cette dernière, puis l’acquittement de la première. Ce qui correspond à ces quatre envois de paquets :
En observant ces paquets rapidement, une étape semble incohérente. En effet, c’est le client qui a l’initiative de la déconnection. Or ici, c’est le serveur qui envoi le premier paquet FIN. En fait, la combinaison de touches <Ctrl + C> envoi un signal de fin de communication au service telnet fonctionnant sur le serveur. Une fois que nous sommes déconnectés du service telnet, nous n’avons plus aucune raison de maintenir la connection TCP avec le serveur, c’est pourquoi celui-ci nous « jette » et possède l’initiative de la déconnexion.
Ø Etudions le premier paquet :
Ce paquet possède le flag ACK acquittant les précédents paquets envoyés par le client, et le numéro d’ACK : 2168761175. Son numéro de séquence est 2430282163. Il a également le flag FIN de positionné.
Ø Lorsque le client reçoit cette annonce de fin de connexion, il l’accepte :
Le flag ACK est donc positionné, et le numéro d’acquittement correspondant au dernier numéro de séquence que le serveur a envoyé, incrémenté de 1 : 2430282164. Le numéro de séquence de ce paquet est le précédent numéro d’acquittement du serveur : 2168761175. Remarquons quelque chose d’également important : tout à l’heure, si vous avez bien regardés, la window size des paquets envoyés par le client était de 4288 octets. Dans ce paquet elle est de 4110. Ce qui est l’exemple concret que la window size est un paramètre qui peut être réajusté à n’importe quel moment de la connexion. A ce stade, la connexion est fermée dans le sens Serveur à Client.
Ø Maintenant que la connexion est fermée dans un sens, il faut la fermer dans l’autre. Le client formule à son tour sa demande de déconnexion :
Ce paquet contient le flag FIN annonçant la déconnexion. Le flag ACK est aussi activé, pour acquitter les précédents paquets envoyés par le serveur (même si le paquet précédent a déjà acquitté les paquets, rappelons que dans une connexion, à partir du second paquet envoyé, le flag ACK est toujours présent). Le numéro d’ACK est le même que précédemment puisque le serveur n’a envoyé aucun paquet : 2430282164. Le numéro de séquence lui correspond également au même que le précédent paquet car aucune donnée n’a été envoyée.
Ø Pour finir, le serveur va alors acquitter la demande de clôture de connexion du client, par un dernier paquet :
Ce paquet contient donc juste le flag ACK et le numéro d’ACK correspondant au précédent numéro de séquence que le client a envoyé incrémenté de 1 : 2168761176. Son numéro de séquence est celui que le client s’attend à recevoir à savoir (d’après son dernier numéro d’ACK) : 2430282164.
Une fois que le client reçoit ce paquet, la connexion est fermée dans le sens Client à Serveur, soit des deux côtés.