TTL, erreurs ICMP, et comment une app en bac à sable y parvient quand même
Un en-tête IPv4 contient un champ TTL de 8 bits (appelé Hop Limit en IPv6) dont l'unique rôle est d'empêcher les paquets de circuler indéfiniment. Chaque routeur qui relaie un paquet le décrémente de un ; à zéro, il jette le paquet et renvoie un message ICMP Time Exceeded, type 11 code 0, émis depuis l'interface par laquelle le paquet est arrivé.
Traceroute transforme ce mécanisme d'échec en mesure. Il envoie une sonde avec un TTL de 1, qui meurt au premier routeur et provoque une erreur qui l'identifie. Puis un TTL de 2, puis 3, en progressant d'un saut à la fois. Trois sondes par TTL produisent les trois temps affichés sur chaque ligne. La détection de la cible dépend du type de sonde : le traceroute BSD de macOS envoie des datagrammes UDP vers des ports hauts improbables à partir de 33434 et considère un ICMP Port Unreachable (type 3, code 3) comme le signal d'arrivée, tandis que tracert sous Windows envoie des ICMP Echo Request et s'arrête sur un Echo Reply. Cette différence n'est pas cosmétique : les pare-feu traitent très différemment les sondes UDP et l'ICMP Echo, si bien qu'une même destination produit légitimement des sauts en astérisques différents depuis un Mac et depuis une machine Windows. Vérifiez les deux avant d'accuser un routeur.
Ce qui mène à la question que tout le monde tranche de travers, y compris une version antérieure de cette page : une application en bac à sable peut-elle seulement faire cela ?
Le raisonnement qui conclut que non tient en trois temps. /usr/sbin/traceroute est installé setuid root sous macOS alors que /sbin/ping ne l'est pas, donc traceroute exigerait des privilèges que ping n'a pas ; le bac à sable n'accorde aucun privilège de ce type ; donc pas de traceroute dans une application App Store. Chaque étape paraît raisonnable et la conclusion est pourtant fausse, car la prémisse confond le type de sonde retenu par le traceroute BSD avec le traceroute en tant que technique. Ce binaire sonde en datagrammes UDP et il lui faut un socket brut pour lire les erreurs ICMP qu'ils provoquent, d'où le setuid. Sondez en ICMP Echo, et les réponses arrivent sur ce même socket ICMP datagramme que le ping utilise déjà sans privilèges. setsockopt(IP_TTL) n'est pas un appel privilégié.
SSHive ne pilote donc aucun binaire système. Il ouvre socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP), positionne le TTL, envoie trois requêtes Echo par palier, et lit ce qui revient : un Time Exceeded qui nomme un routeur, une réponse Echo signifiant que la destination a répondu, ou rien en deux secondes, ce qui s'affiche en astérisque. Tout cela a été mesuré sous sandbox-exec avec les entitlements réels de l'application avant d'être livré, et a révélé un piège qui mérite d'être répété : avec com.apple.security.network.client seul, la sonde part et la réponse est refusée en EPERM, un échec silencieux qui ressemble exactement à un réseau filtrant. com.apple.security.network.server est également nécessaire. SSHive déclare les deux, et c'est pourquoi la version App Store, sous bac à sable, trace vraiment au lieu d'aligner une colonne d'astérisques.
iOS arrive au même point par le même chemin. Network.framework expose TCP, UDP, QUIC et TLS, et aucun ICMP, mais ce n'est pas la seule API disponible : la couche de sockets BSD en dessous accepte le même socket ICMP datagramme, et l'exemple SimplePing d'Apple le démontre depuis des années. Les versions iPhone et iPad exécutent la même boucle de trente sauts et trois sondes que le Mac.
Connaissez les limites avant de vous y fier : plafond fixe de 30 sauts, aucune option de protocole, de port ou de nombre de sondes, et aucun enrichissement ASN ou géographique. Comme les sondes sont des ICMP Echo plutôt que de l'UDP, un pare-feu qui autorise l'un et jette l'autre peut produire un motif d'astérisques différent de celui de /usr/sbin/traceroute ; aucun des deux résultats n'est faux, et les comparer est parfois la façon dont on trouve le pare-feu.