flyingroutes : une alternative à traceroute plus rapide

Traductions

Sommaire

Dans cet article, je vous présente un outil de diagnostic réseau que j’ai développé : flyingroutes. L’objectif est de fournir un moyen efficace pour déterminer les nœuds traversés lors d’une communication réseau grâce à une alternative plus rapide au célèbre outil traceroute.

Introduction

Le diagnostic est une part importante du travail d’un administrateur des réseaux. Pour ce faire, de nombreux outils existent par exemple pour vérifier la présence d’un hôte sur le réseau, découvrir les services qu’un hôte offre, trouver les chemins pour atteindre un hôte ou encore découvrir la quantité de données pouvant être transmise par paquet de données envoyé sur le réseau. Nous nous intéressons ici à la fonction de découverte d’un chemin réseau d’un hôte émetteur vers un hôte destination. Nous reviendrons d’abord sur le fonctionnement du célèbre outil traceroute avant de découvrir l’alternative que j’ai développée : flyingroutes.

Aux origines de traceroute

traceroute est avec ping l’utilitaire réseau le plus connu et utilisé par les administrateurs des réseaux. La version originale date de 1987 et fut développée d’abord au Lawrence Berkeley National Laboratory (LBNL) de l’Université de Californie. traceroute permet l’envoi de paquets sur un réseau Internet Protocol (IP) séquentiellement vers une cible donnée en augmentant la valeur du champ IP Time To Live (TTL), commençant à 1 et allant jusqu’à n, n étant le nombre de nœuds, sauts ou hops traversés jusqu’à et incluant la cible. A chaque fois qu’un paquet atteint un nœud, celui-ci modifie la valeur du champ TTL en la décrémentant de 1 et si la valeur atteint 0, le paquet reçu n’est pas transmis au nœud suivant et une réponse Internet Control Message Protocol (ICMP) spécifique de type TTL exceeded est envoyée à l’émetteur. Ainsi, le premier paquet est ignoré par le premier nœud, le deuxième paquet est ignoré par le deuxième nœud et ainsi de suite jusqu’à ce que la valeur de n soit suffisamment grande pour finalement atteindre la cible qui offrira une réponse adéquate. Les paquets IP envoyés peuvent contenir des messages reposant sur les protocoles ICMP, User Datagram Protocol (UDP) ou Transmission Control Protocol (TCP). Ce fonctionnement est illustré par la figure ci-dessous.

Fonctionnement de traceroute

Si dans la plupart des cas un message ICMP TTL exceeded est renvoyé par les nœuds sur le chemin, parfois ceux-ci ne répondent pas à ce mécanisme et ne renvoient pas de message. Ceci se traduit par la présence des fameuses petites étoiles (*) dans le retour de la commande. Et c’est là que l’administrateur réseau a parfois le temps d’aller se faire couler un café si les étoiles se multiplient ! Même en configurant un temps d’attente (avec l’option -w) j’ai dû attendre près de 3 minutes avant d’avoir le retour complet de la commande ci-dessous.

$ time traceroute thibautprobst.fr
traceroute: Warning: thibautprobst.fr has multiple addresses; using 99.86.91.20
traceroute to thibautprobst.fr (99.86.91.20), 64 hops max, 52 byte packets
 1  lan.home (192.168.1.254)  6.598 ms  2.960 ms  2.991 ms
 2  80.10.237.205 (80.10.237.205)  7.750 ms  4.375 ms  4.004 ms
 3  lag-10.neblc00z.rbci.orange.net (193.253.84.82)  14.324 ms  5.207 ms  5.010 ms
 4  ae87-0.nctou201.rbci.orange.net (193.253.83.242)  13.275 ms  12.602 ms  5.830 ms
 5  ae43-0.nipoi201.rbci.orange.net (193.252.160.49)  14.314 ms  12.417 ms  14.346 ms
 6  193.252.137.18 (193.252.137.18)  18.060 ms  16.425 ms  17.128 ms
 7  99.83.114.168 (99.83.114.168)  26.709 ms
    193.251.248.38 (193.251.248.38)  18.959 ms
    193.251.248.36 (193.251.248.36)  19.835 ms
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
15  * * *
16  * * *
17  * * *
18  server-99-86-91-20.cdg50.r.cloudfront.net (99.86.91.20)  20.457 ms * *

real	2m40.437s
user	0m0.004s
sys     0m0.018s

Alors, que fait-on si on n’aime pas le café ou si on est pas très patient ?

Une alternative plus rapide : flyingroutes

C’est là où je propose une alternative avec flyingroutes. Vous n’avez alors plus à attendre le retour complet de votre commande traceroute ! En effet, vous obtenez un résultat similaire en … près de 3 secondes !

$ time python3 flyingroutes thibautprobst.fr
flyingroutes to thibautprobst.fr (99.86.91.101) with 30 hops max (3 packets per hop) on ICMP with a timeout of 2.0s
thibautprobst.fr (99.86.91.101) reached in 20 hops
Hop 1:  192.168.1.254 (lan.home) - 25.36ms
Hop 2:  80.10.237.205 - 24.81ms
Hop 3:  193.253.84.82 (lag-10.neblc00z.rbci.orange.net) - 25.5ms
Hop 4:  193.253.83.242 (ae87-0.nctou201.rbci.orange.net) - 24.57ms
Hop 5:  193.252.160.49 (ae43-0.nipoi201.rbci.orange.net) - 25.82ms
Hop 6:  193.252.137.18 - 29.2ms
Hop 7:  193.251.248.148 - 32.28ms
Hop 8:  * * * * * * * *
Hop 9:  * * * * * * * *
Hop 10: * * * * * * * *
Hop 11: * * * * * * * *
Hop 12: * * * * * * * *
Hop 13: * * * * * * * *
Hop 14: * * * * * * * *
Hop 15: * * * * * * * *
Hop 16: * * * * * * * *
Hop 17: * * * * * * * *
Hop 18: * * * * * * * *
Hop 19: * * * * * * * *
Hop 20: 99.86.91.101 (server-99-86-91-101.cdg50.r.cloudfront.net) - 20.78ms


real	0m3.271s
user	0m0.168s
sys     0m0.049s

Pour ce faire, j’évite tout simplement la méthode séquentielle de traceroute. En effet, j’envoie en fait simultanément un ensemble de paquets avec différentes valeurs de TTL (entre 1 et n, avec n égal à 30 par défaut mais que vous pouvez déterminer) et j’attend toutes les réponses des nœuds qui sont alors associées aux requêtes initiales. Le tout est rendu possible grâce à du multithreading). Les réponses reçues peuvent être :

  • ICMP TTL exceeded en cas de TTL expiré sur un nœud ;
  • ICMP Echo Reply en cas de réponse à une requête ICMP Echo Request ;
  • ICMP Destination unreachable (Port unreachable) en cas de réponse à une requête UDP ;
  • TCP SYN/ACK en cas de requête TCP SYN à laquelle un service répond sur la cible ;
  • TCP RST en cas de requête TCP SYN à laquelle aucun service ne répond sur la cible.

Fonctionnement de flyingroutes

Le défi de flyingroutes réside dans la ré-association des réponses avec les requêtes initiales. En effet, le parallélisme induit la possibilité de recevoir les réponses dans le désordre et demande donc d’utiliser des indicateurs pour se repérer. Voici comment j’ai relevé le défi dans chaque cas.

  • En ICMP :
    • Association des requêtes ICMP Echo request aux réponses ICMP TTL exceeded : je retiens la somme de contrôle ou checksum ICMP calculée et envoyée dans les requêtes ICMP Echo Request puis je lis la valeur de ce checksum stocké dans les données utiles ou payload des réponses ICMP TTL exceeded reçues.
    • Association des requêtes ICMP Echo request aux réponses ICMP Echo Reply : je stocke dans la payload des requêtes ICMP Echo Request la valeur du TTL IP car cette payload est renvoyée dans les réponses ICMP Echo Reply que je lis.
  • En UDP :
    • Association des requêtes UDP aux réponses ICMP TTL exceeded : je retiens le port UDP source utilisé pour envoyer les requêtes UDP puis je lis la valeur de ce port qui est stocké dans les données utiles ou payload des réponses ICMP TTL exceeded reçues.
    • Association des requêtes UDP aux réponses ICMP Destination unreachable (Port unreachable) : je retiens le port UDP source utilisé pour envoyer les requêtes UDP puis je lis la valeur de ce port qui est stocké dans les données utiles ou payload des réponses ICMP Destination unreachable (Port unreachable).
  • En TCP :
    • Association des requêtes TCP SYN aux réponses ICMP TTL exceeded : j’essaye d’établir des sessions TCP par envoi de paquets TCP SYN, puis pour chacune de ces sessions je vérifie son état (établie ou non) par envoi de données et vérification du résultat : si la session est ouverte, l’envoi est possible et je retiens alors le port TCP source utilisé pour envoyer les messages TCP puis je lis la valeur de ce port qui est stocké dans les données utiles ou payload des réponses ICMP TTL exceeded reçues.
    • Association des requêtes TCP SYN aux réponses TCP SYN/ACK : j’essaye d’établir des sessions TCP par envoi de paquets TCP SYN, puis pour chacune de ces sessions je vérifie son état (établie ou non) par envoi de données et vérification du résultat : si la session n’est pas ouverte, l’envoi est impossible donc aucune réponse TCP SYN/ACK n’a été reçue.

En plus de pouvoir fixer le nombre de nœuds maximum à tester, flyingroutes supporte, comme vous l’aurez compris, ICMP, UDP et TCP. On peut même utiliser les trois protocoles en même temps, ce qui premet de maximiser les chances de découvertes des nœuds et est une fonctionnalité qui n’est, à ma connaissance, offerte par aucun outil similaire. On peut aussi choisir le port utilisé pour UDP et TCP (33434 par défaut), spéficier une valeur de timeout pour ceux qui sont vraiment impatients au risque de réduire ses chances de découverte de nœud (la valeur par défaut étant 2s) et préciser le nombre de paquets envoyés par valeur de TTL (3 par défaut, cela permettant de voir si différents chemins existent par nœud en faisant varier le port). En outre, notez que flyingroutes est développé en Python (version 3.10 minimum requise) et donc supporté sur MacOS, Linux et Windows.

$ python3 flyingroutes.py -h
usage: flyingroutes.py [-h] [--number_of_hops NUMBER_OF_HOPS] [--protocol PROTOCOL] [--dest_port DEST_PORT] [--timeout TIMEOUT] [--repeat REPEAT] HOST

positional arguments:
  HOST                  target host

options:
  -h, --help            show this help message and exit
  --number_of_hops NUMBER_OF_HOPS, -n NUMBER_OF_HOPS
                        Max number of hops allowed to reach the target (default: 30)
  --protocol PROTOCOL, -p PROTOCOL
                        Protocol to use: ICMP, UDP, TCP or ALL of them (default: ICMP)
  --dest_port DEST_PORT, -d DEST_PORT
                        Port to use for UDP and TCP only (default: 33434), increased by 1 for each additional packets sent with the --repeat option
  --timeout TIMEOUT, -t TIMEOUT
                        Timeout for responses (default: 2s)
  --repeat REPEAT, -r REPEAT
                        Number of packets to repeat per TTL value increase using different destination ports (default: 3, max: 16)

Gardez un œil sur le dépôt GitHub car d’autres fonctionnalités sont à venir ! N’hésitez pas d’ailleurs à faire des demandes de nouvelles fonctionnalités ou à reporter des bugs ici. flyingroutes est un assez jeune projet donc j’ai besoin de retours constructifs !

Voici quelques exemples d’utilisation de flyingroutes.

$ python3 flyingroutes.py example.com -p tcp -d 443 -r 5 -n 20
flyingroutes to example.com (93.184.216.34) with 20 hops max (5 packets per hop) on TCP port 443 with a timeout of 2.0s
example.com (93.184.216.34) reached in 13 hops
Hop 1:  192.168.1.254 (lan.home) - 40.29ms
Hop 2:  * * * * * * * *
Hop 3:  * * * * * * * *
Hop 4:  193.253.83.242 (ae87-0.nctou201.rbci.orange.net) - 159.63ms
Hop 5:  193.252.160.49 (ae43-0.nipoi201.rbci.orange.net) - 267.23ms
Hop 6:  193.252.137.18 - 491.86ms
Hop 7:  129.250.66.144 (ae-26.a01.parsfr05.fr.bb.gin.ntt.net) - 365.06ms
Hop 8:  129.250.2.178 (ae-15.r20.parsfr04.fr.bb.gin.ntt.net) - 687.11ms
        129.250.2.106 (ae-15.r21.parsfr04.fr.bb.gin.ntt.net) - 590.88ms
Hop 9:  129.250.6.6 (ae-13.r24.asbnva02.us.bb.gin.ntt.net) - 866.76ms
        129.250.4.194 (ae-14.r21.nwrknj03.us.bb.gin.ntt.net) - 726.34ms
Hop 10: 129.250.3.17 (ae-1.a02.nycmny17.us.bb.gin.ntt.net) - 1238.61ms
        129.250.2.145 (ae-0.a04.asbnva02.us.bb.gin.ntt.net) - 1079.23ms
        129.250.3.242 (ae-0.a05.asbnva02.us.bb.gin.ntt.net) - 942.95ms
Hop 11: 129.250.192.98 (ce-1-1-3.a05.asbnva02.us.ce.gin.ntt.net) - 1118.77ms
        128.241.1.90 (ce-0-13-0-3.r01.nycmny17.us.ce.gin.ntt.net) - 825.45ms
        128.241.1.14 (ce-0-3-0.a02.nycmny17.us.ce.gin.ntt.net) - 785.09ms
Hop 12: 152.195.65.129 (ae-66.core1.dcb.edgecastcdn.net) - 1351.22ms
        152.195.64.129 (ae-65.core1.dcb.edgecastcdn.net) - 1292.69ms
        152.195.68.131 (ae-65.core1.nyb.edgecastcdn.net) - 1039.99ms
        152.195.69.131 (ae-66.core1.nyb.edgecastcdn.net) - 1000.56ms
Hop 13: 93.184.216.34 - 101.79ms
$ python3 flyingroutes.py 8.8.8.8 -p udp -r 1
flyingroutes to 8.8.8.8 (8.8.8.8) with 30 hops max (1 packets per hop) on UDP port 33434 with a timeout of 2.0s
8.8.8.8 (8.8.8.8) reached in 11 hops
Hop 1:  192.168.1.254 (lan.home) - 23.69ms
Hop 2:  80.10.237.205 - 34.01ms
Hop 3:  193.253.84.82 (lag-10.neblc00z.rbci.orange.net) - 30.41ms
Hop 4:  193.253.83.242 (ae87-0.nctou201.rbci.orange.net) - 49.86ms
Hop 5:  193.252.160.49 (ae43-0.nipoi201.rbci.orange.net) - 49.87ms
Hop 6:  193.252.160.46 (ae40-0.nipoi202.rbci.orange.net) - 59.34ms
Hop 7:  193.252.137.14 - 78.51ms
Hop 8:  74.125.50.250 - 98.09ms
Hop 9:  108.170.244.161 - 129.06ms
Hop 10: 142.251.49.135 - 108.13ms
Hop 11: 8.8.8.8 (dns.google) - 27.62ms
$ python3 flyingroutes.py thibautprobst.fr -t 3
flyingroutes to thibautprobst.fr (99.86.91.20) with 30 hops max (3 packets per hop) on ICMP with a timeout of 3.0s
thibautprobst.fr (99.86.91.20) reached in 18 hops
Hop 1:  192.168.1.254 (lan.home) - 65.18ms
Hop 2:  80.10.237.205 - 60.73ms
Hop 3:  193.253.84.82 (lag-10.neblc00z.rbci.orange.net) - 56.52ms
Hop 4:  193.253.83.242 (ae87-0.nctou201.rbci.orange.net) - 65.61ms
Hop 5:  193.252.160.49 (ae43-0.nipoi201.rbci.orange.net) - 57.91ms
Hop 6:  193.252.137.18 - 88.39ms
Hop 7:  193.251.248.38 - 75.2ms
Hop 8:  * * * * * * * *
Hop 9:  * * * * * * * *
Hop 10: * * * * * * * *
Hop 11: * * * * * * * *
Hop 12: * * * * * * * *
Hop 13: * * * * * * * *
Hop 14: * * * * * * * *
Hop 15: * * * * * * * *
Hop 16: * * * * * * * *
Hop 17: * * * * * * * *
Hop 18: 99.86.91.20 (server-99-86-91-20.cdg50.r.cloudfront.net) - 51.61ms
$ python3 flyingroutes.py thibautprobst.fr -p all
flyingroutes to thibautprobst.fr (54.230.112.104) with 30 hops max (1 packets per hop) on ICMP, UDP port 33434 and TCP port 33434 with a timeout of 2.0s
thibautprobst.fr (54.230.112.104) reached in 21 hops
Hop 1:  192.168.41.191 - ICMP: 39.92ms, UDP: 39.83ms, TCP: 39.59ms
Hop 2:  255.0.0.0 - ICMP: 57.34ms, UDP: 57.2ms, TCP: 56.93ms
Hop 3:  * * * * * * * * - ICMP, UDP and TCP
Hop 4:  255.0.0.1 - ICMP: 160.43ms, UDP: 160.27ms, TCP: 159.69ms
Hop 5:  255.0.0.2 - ICMP: 76.01ms
        255.0.0.4 - UDP: 132.48ms, TCP: 132.17ms
Hop 6:  255.0.0.3 - ICMP: 85.11ms
        10.216.10.65 - UDP: 169.85ms
Hop 7:  255.0.0.4 - ICMP: 68.35ms
        81.253.184.106 (ae31-760.ngesevir01.rbci.orange.net) - UDP: 150.83ms
Hop 8:  193.251.110.185 (ae31-0.nclyo201.rbci.orange.net) - UDP: 106.85ms
Hop 9:  193.252.101.145 (ae41-0.nilyo101.rbci.orange.net) - UDP: 108.51ms
Hop 10: 81.253.184.86 - UDP: 146.15ms
        193.252.101.65 (ae58-0.nilyo101.rbci.orange.net) - TCP: 127.85ms
Hop 11: 193.251.255.186 (amazon-34.gw.opentransit.net) - UDP: 169.31ms
        81.253.184.86 - TCP: 137.89ms
Hop 12: 81.253.184.86 - ICMP: 119.5ms
Hop 13: * * * * * * * * - ICMP, UDP and TCP
Hop 14: * * * * * * * * - ICMP, UDP and TCP
Hop 15: * * * * * * * * - ICMP, UDP and TCP
Hop 16: * * * * * * * * - ICMP, UDP and TCP
Hop 17: * * * * * * * * - ICMP, UDP and TCP
Hop 18: * * * * * * * * - ICMP, UDP and TCP
Hop 19: * * * * * * * * - ICMP, UDP and TCP
Hop 20: * * * * * * * * - ICMP, UDP and TCP
Hop 21: 54.230.112.104 (server-54-230-112-104.mrs52.r.cloudfront.net) - ICMP: 138.65ms

Conclusion

A travers cet article, nous avons découvert flyingroutes, une alternative à traceroute qui permet l’envoi en parallèle de requêtes afin de déterminer plus rapidement le chemin et les nœuds empruntés pour atteindre une cible sur le réseau. Une fois encore, j’appelle à votre bon scepticisme car il existe beaucoup d’autres bon outils de diagnostic similaires à traceroute ou flyingroutes qui satisfairont probablement vos besoins. Je pense notamment à tracepath, mtr, mtraceroute ou Trippy. Je vous invite d’ailleurs à lire cet excellent article qui présente très bien ces outils et leurs usages.

Sources

Traductions