1 points par GN⁺ 4 시간 전 | 1 commentaires | Partager sur WhatsApp
  • La zone IPv6 est une notation qui permet d’identifier l’interface cible, comme dans fe80::4%eth0, lorsque plusieurs interfaces utilisent la même portée link-local fe80::
  • Dans une URL, une adresse IPv6 est entourée de crochets, comme [fe80::4]:80, pour distinguer les deux-points de ceux du port ; en ajoutant la zone, la notation entre crochets devient [fe80::4%eth0]:80
  • Le module net/url de Go interprète ]:80 comme un escape URL invalide %et, ce qui provoque une erreur invalid URL escape
  • La RFC 6874 définit un littéral IPv6 avec zone comme IPv6address "%25" ZoneID, donc dans une URL, le % doit être percent-encodé en %25
  • Pour qu’Anubis puisse pointer vers une adresse IPv6 avec zone, il faut utiliser cette notation ; cela reste un cas limite qui implique aussi la compatibilité des origin et des bibliothèques, comme le montrent les problèmes liés aux navigateurs, à nginx et à Requests

Conflit entre la zone IPv6 et la syntaxe des URL

  • Les adresses link-local IPv6 peuvent exister dans la plage fe80::whatever sur chaque interface ; ainsi, lorsqu’il y a deux interfaces réseau, il faut utiliser une scope/zone IPv6) pour distinguer une destination fe80::4
  • Le format de la valeur de zone varie selon le système d’exploitation : Linux utilise le nom de l’interface, Windows l’identifiant de l’interface
  • Dans l’exemple, eth0 est le nom du périphérique Ethernet, et l’adresse s’écrit ainsi
fe80::4%eth0
  • L’hôte et le port sont normalement séparés par des deux-points, mais comme les adresses IPv6 utilisent elles aussi des deux-points pour séparer les groupes hexadécimaux, fe80::4 avec le port 80 doit être entouré de crochets comme suit
[fe80::4]:80
  • En ajoutant la zone, on obtient le format suivant
[fe80::4%eth0]:80
  • Si on l’insère directement dans le nom d’hôte d’une URL, http://[fe80::4%eth0]:80 échoue dans Go net/url, car %et est interprété à tort comme un escape URL invalide
panic: parse "http://[fe80::4%eth0]:80";: invalid URL escape "%et"

Solution standard et problèmes restants

  • Les valeurs non conformes à la syntaxe des URL doivent utiliser le percent-encoding ; %20 dans une URL est par exemple l’encodage d’un espace ASCII, invalide tel quel dans une URL
  • Comme le % de la zone IPv6 doit lui aussi être encodé, il faut écrire en Go http://[fe80::4%25eth0]:80 pour que Hostname() renvoie fe80::4%eth0
  • La RFC 9844 fournit des recommandations pour la gestion des zones IPv6 dans les interfaces utilisateur, et la RFC 6874 définit comme suit la syntaxe d’un littéral IPv6 avec zone dans une URL
IP-literal = "[" ( IPv6address / IPv6addrz / IPvFuture  ) "]"

ZoneID = 1*( unreserved / pct-encoded )

IPv6addrz = IPv6address "%25" ZoneID
  • On retrouve le même cas limite dans le ticket nginx, l’issue Requests et le brouillon BCP sur les URI HTTP link-local
  • Les navigateurs ne prennent actuellement pas en charge les zones IPv6, car cela casse le concept d’« origin », utilisé dans de nombreux comportements subtils ; ce brouillon tente donc de définir les origin de zone IPv6 pour permettre un usage dans les navigateurs
  • Pour qu’Anubis puisse pointer vers une adresse IPv6 avec zone, le % doit être percent-encodé et, tant que la politique reste de ne pas forker la bibliothèque standard de Go, il faut accepter la mauvaise UX de ce cas limite

1 commentaires

 
GN⁺ 4 시간 전
Commentaires sur Lobste.rs
  • J’ai l’impression qu’une conclusion du genre TL;DR: les ordinateurs étaient une erreur relève un peu du bébé jeté avec l’eau du bain
    Littéralement, c’est une logique de méchant d’anime à la Trigun : puisque les humains peuvent commettre des crimes atroces, il faudrait éliminer tous les humains
    Je sais que c’est formulé sur le ton de la blague, mais je trouve ça intéressant, et je pense en faire le sujet de ma prochaine présentation en préparation
    • Le titre est effectivement très dramatique et putaclic
      Cela dit, je suis d’accord sur le fond. La situation en elle-même est quand même assez ridicule
  • Le fait de ne pas pouvoir traiter correctement les adresses IPv6 à portée link-local dans une URL est une erreur
    Cela dit, les cas où l’on ne gère pas correctement les adresses IPv6 link-local ne sont pas si rares
    • À l’inverse, gérer la zone dans une adresse IPv6 à l’intérieur d’une URL augmente pas mal la complexité
      En effet, % prend alors un sens différent uniquement dans la partie hôte de l’URL, et encore seulement si l’hôte est une adresse IPv6 entre [...]
      La grammaire peut toujours rester non ambiguë, mais ce n’est pas là l’essentiel. Plus on accumule ce genre de cas particuliers, plus un parseur d’URL risque d’en oublier un, et plus les différences entre parseurs peuvent laisser se glisser des bugs sales ou des problèmes de sécurité
      Personnellement, je préfère qu’on gère les zones IPv6 dans les URL, mais comme il y a déjà eu à une époque des recommandations imposant d’encoder % dans une URL, revenir en arrière introduirait aujourd’hui de vraies ambiguïtés. C’est regrettable
  • Toute bibliothèque ou implémentation compatible avec RFC 3986 rencontrera ce problème, parce que la spécification définit ainsi les séquences encodées en pourcentage
    pct-encoded = "%" HEXDIG HEXDIG
    Ici, HEXDIG est défini comme [a-fA-F], donc %et est analysé comme une séquence invalide
    La spécification dit aussi que le caractère % sert d’indicateur pour un octet encodé en pourcentage ; pour l’utiliser comme donnée dans un URI, il faut donc l’encoder en %25. Si une chaîne déjà décodée est décodée une nouvelle fois, un octet de donnée % peut être pris à tort pour le début d’un encodage en pourcentage ; et si une chaîne déjà encodée est réencodée, on obtient le problème inverse. L’implémentation ne doit donc pas encoder ni décoder la même chaîne plus d’une fois
    Donc oui, c’est agaçant, mais en pratique j’ai du mal à y voir un bug
  • Je ne vois pas pourquoi utiliser directement % dans une adresse avec zone serait si terrible. Les caractères encodés sont aussi autorisés dans la partie hôte, et utiliser % tel quel dans une adresse de zone crée une ambiguïté
    % n’est pas lui-même un caractère non réservé, donc il est normal de l’encoder en pourcentage
    Ce n’est pas vraiment nouveau que net/url et net/http de Go entrent en conflit avec la RFC des URL. L’existence même de net/url.URL.Path et son usage dans net/http sont particulièrement pénibles, car cela casse %2F. net/http.Redirect utilise aussi path.Clean, ce qui replie à tort // en /
    Il y a beaucoup de raisons d’avoir envie de forker les parties de la bibliothèque standard de Go qui manipulent des URL, ou de proposer quelque chose comme net/url/v2. Mais à en juger par cet article, la gestion par Go des adresses IPv6 avec zone semble raisonnable et correcte