Résumé

  • Une même valeur d’adresse IPv6 à portée limitée peut exister dans plusieurs zones. Le nœud ajoute donc un index de zone distinct des 128 bits, le résout dans son propre espace d’interfaces et ne l’insère pas dans le paquet.
  • La RFC 6874 a tenté en 2013 d’introduire ce ZoneID local dans la syntaxe des URI. La RFC 9844 a jugé cette voie impraticable en 2025 et l’a remplacée par une obligation d’interface utilisateur : saisir, valider et convertir le choix local sans lui conférer une identité globale.

Une note exacte au mauvais endroit

Un rapport d’incident peut indiquer qu’un équipement a été joint par fe80::1%eth0. La notation est précise pour la machine qui a exécuté la commande : elle nomme une adresse et le chemin local retenu. Elle ne constitue pourtant pas une coordonnée universelle. Sur un autre hôte, eth0 peut désigner un autre lien ou ne pas exister.

La raison tient au rôle des adresses link-local. La RFC 4291 les limite à un seul lien et interdit aux routeurs de transférer vers un autre lien un paquet dont la source ou la destination est link-local. Deux liens séparés peuvent ainsi héberger chacun la même valeur fe80::1 sans prétendre représenter le même point global.

La RFC 4007, publiée en mars 2005, fournit la distinction décisive. La portée, ou scope, décrit la taille d’une région topologique. Une zone est une instance particulière d’une région de cette portée. « Link-local » indique donc une taille ; « ce lien-ci » désigne une zone.

Lorsqu’un nœud appartient à plusieurs zones de même portée, l’adresse seule ne choisit plus. Le nœud attribue des index à ses zones. Ces index sont strictement locaux : même aux deux extrémités du même câble, ils n’ont pas besoin de coïncider.

La marge %eth0 n’est donc pas inexacte. Elle est exacte dans un domaine beaucoup plus petit que la chaîne qui la porte. L’erreur commence quand un outil conserve les caractères mais oublie la juridiction dans laquelle ils avaient un sens.

Une chaîne de garde locale

L’identifiant de zone suit une chaîne de garde courte. L’utilisateur ou l’automate exprime un choix ; l’interface contrôle sa forme ; le système le convertit en index ; la couche IP applique la portée ; le correspondant ne reçoit jamais le vocabulaire local du départ.

Chaque maillon peut établir un fait plus petit que le suivant. Accepter la saisie ne prouve pas la résolution. Résoudre le nom ne prouve pas que l’interface est active. Envoyer sur cette interface ne prouve pas l’identité du destinataire. Une exploitation fiable conserve ces limites au lieu de résumer le tout par « adresse valide ».

L’adresse qui ne voyageait pas avec sa marge n’était pas incomplète au sens du protocole. Elle refusait de faire porter au réseau la cartographie privée d’un hôte. Sa marge reste indispensable à celui qui agit, et précisément pour cette raison, elle ne peut devenir le titre universel de ce qu’il cherche.

L’API avait déjà séparé les responsabilités

Avant que la notation ne rencontre les navigateurs, l’interface de programmation avait donné au contexte local sa propre case. La RFC 3493, en février 2003, définit dans sockaddr_in6 un champ sin6_addr pour l’adresse et un champ sin6_scope_id de 32 bits pour le sélecteur de portée.

Cette disposition empêche une fiction commode : l’index ne prolonge pas l’adresse IPv6. Il accompagne l’appel système. Le noyau l’utilise pour choisir une zone locale, puis émet un paquet dont l’adresse reste une valeur IPv6 ordinaire.

La même RFC normalise le passage d’un nom d’interface à un numéro local. if_nametoindex() interroge la machine qui exécute le programme. Un nom inconnu échoue ; il n’est pas résolu dans un registre Internet ni demandé au voisin. Le nom lisible appartient à l’environnement d’exécution, et le nombre produit appartient au noyau de ce même environnement.

RFC 4007 recommande la forme textuelle <address>%<zone_id>. Les implémentations devraient accepter un entier décimal non négatif et peuvent reconnaître des chaînes propres au système, telles que des noms d’interfaces. Comme l’adresse indique déjà sa portée, le suffixe n’a besoin de distinguer que les zones de cette portée.

Le texte interdit toutefois d’étendre cette commodité sans limite. Un identifiant de zone n’a pas de sens pour une adresse globale et ne devrait pas accompagner l’adresse de bouclage. Surtout, la forme textuelle reste interne à un nœud et ne doit pas être transmise, sauf accord préalable de tous ceux qui l’interpréteraient.

Valider ce qui n’a pas de grammaire universelle

RFC 4007 laissait le jeu de caractères, la longueur et la signification des identifiants non numériques aux implémentations. Cette souplesse accueille les conventions des systèmes, mais elle empêche de déléguer la sécurité à une grammaire mondiale qui n’existe pas.

RFC 9844 demande aux interfaces d’imposer une longueur appropriée et de rejeter les entrées dangereuses, notamment NUL. L’erratum held 8553 de RFC 4007 relève précisément l’absence de ces limites et renvoie aux recommandations de sécurité plus récentes.

Un suffixe peut traverser un formulaire, une ligne de commande, un fichier, un journal, un analyseur d’URI et une API système. Chaque couche peut échapper, tronquer ou normaliser. L’application doit vérifier que la valeur présentée à l’utilisateur est celle qui a produit l’index remis au noyau.

Une opération réussie via %eth0 constitue une preuve bornée : sur cet hôte, à cet instant, ce nom s’est résolu et le chemin a fonctionné pour cette opération. Elle n’authentifie pas le pair, ne prouve pas la propriété de l’adresse, ne garantit pas la portée globale et ne rend pas le nom transférable.

Canoniser l’adresse ne canonise pas son contexte

La RFC 5952 a réduit en 2010 les variantes d’écriture d’une adresse IPv6 : compression des zéros, choix de casse et règles utiles aux journaux et aux configurations. Elle a également rappelé l’usage des crochets lorsqu’une adresse littérale est associée à un port.

Cette canonicalisation s’arrête aux bits de l’adresse. RFC 9844 précise qu’elle ne couvre pas l’extension de zone issue de RFC 4007. Deux écritures canoniques identiques peuvent encore nécessiter des choix de zone différents ; deux suffixes identiques sur des machines différentes peuvent désigner des interfaces sans relation.

Le défaut local n’est pas davantage une convention portable. RFC 4007 conseille des zones par défaut, généralement représentées par zéro. RFC 9844 constate pourtant que tous les systèmes n’en fournissent pas une utilisable et cite Linux. Une application qui fonctionne sans suffixe dans un environnement n’a donc pas démontré que le contexte était inutile, seulement qu’un acteur local l’a fourni implicitement.

Pour un audit, trois éléments doivent rester distincts : la valeur d’adresse, l’identifiant saisi par l’opérateur et l’index effectivement obtenu sur l’hôte. Réduire ces éléments à une « adresse normalisée » rend la comparaison plus simple mais supprime la décision qui a déterminé le chemin.

Quand la marge est entrée dans l’URI

La syntaxe des URI a posé un conflit de nature. La RFC 3986, en janvier 2005, décrit un identifiant à portée globale, même si certaines actions peuvent dépendre du contexte de l’utilisateur. Elle réserve aussi % à l’encodage en pourcentage ; un signe pour cent littéral placé dans les données devient %25.

La RFC 6874 a proposé en 2013, dans un URI HTTP, un littéral entre crochets tel que [fe80::a%25en1]. Le %25 représente le séparateur %, suivi du ZoneID local. L’objectif était de permettre à des interfaces, notamment des navigateurs, de viser commodément un équipement link-local.

Le document reconnaissait déjà que le ZoneID n’avait de sens qu’au nœud d’origine et devait être retiré avant l’envoi d’une requête HTTP. Une donnée affichée à l’intérieur de l’URI devait donc cesser d’en faire partie au moment où l’URI gouvernait une communication extérieure.

Cette tension se propageait aux couches voisines. Fallait-il inclure le suffixe dans la comparaison d’origine ? Le conserver dans l’historique ou un favori ? Le remettre à un proxy ? Le décoder avant ou après l’analyse de l’hôte littéral ? Un double décodage de %25 pouvait transformer une précaution syntaxique en nouvelle ambiguïté.

Le choix du caractère n’était pas le cœur du problème. Une instruction liée au poste local se retrouvait dans une forme conçue pour être échangée, comparée et conservée bien au-delà de ce poste.

Une obligation d’interface, pas une nouvelle URL

En août 2025, la RFC 9844 a complètement rendu RFC 6874 obsolète. Les responsables d’implémentations de navigateurs avaient jugé son approche impraticable. Le texte annule également la mise à jour de RFC 3986 ; l’erratum vérifié 8552 de RFC 6874 enregistre cette correction de statut.

La solution ne cherche plus un meilleur échappement. Toute interface utilisateur qui accepte une adresse autre qu’une adresse globale unicast doit permettre à l’utilisateur de saisir ou de choisir l’identifiant de zone. La forme complète avec % reste préférée, mais un champ séparé, une liste, un autre séparateur ou un paramètre distinct peuvent exprimer la même décision.

L’interface conserve séparément l’adresse et la zone, traduit celle-ci en index d’interface local et devrait signaler un identifiant invalide. Le POSIX inet_pton() ne sait pas convertir seul fe80::1%eth0. L’application doit employer getaddrinfo(), ou séparer la chaîne et associer inet_pton() à if_nametoindex().

RFC 9844 exclut explicitement la sémantique de récupération d’URI par les navigateurs. Elle standardise la façon de recueillir un contexte local, non la façon d’en faire une origine HTTP. Le suffixe demeure indépendant de l’adresse et ne part pas sur le réseau.

Ce recul syntaxique est un progrès architectural. L’interface qui connaît l’utilisateur recueille son intention ; le système qui connaît les interfaces la traduit ; le protocole transporte uniquement ce que le correspondant peut interpréter.

Sources