1 pontos por GN⁺ 4 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Zone de IPv6 é uma notação usada para distinguir a interface de destino, como em fe80::4%eth0, quando várias interfaces usam o mesmo escopo link-local fe80::
  • Em URLs, endereços IPv6 são envolvidos por colchetes, como [fe80::4]:80, para diferenciar a porta dos dois-pontos do endereço; ao adicionar a zone, a notação entre colchetes vira [fe80::4%eth0]:80
  • O net/url do Go interpreta ]:80 incorretamente como um escape de URL %et, gerando o erro invalid URL escape
  • A RFC 6874 define um literal IPv6 com zone como IPv6address "%25" ZoneID, então, em URLs, o % deve ser percent-encoded como %25
  • Para o Anubis apontar para um endereço IPv6 com zone, é preciso usar essa notação; isso continua sendo um caso de borda que também envolve compatibilidade de origin e bibliotecas, como em problemas relacionados a navegador, nginx e Requests

Conflito entre zone de IPv6 e a sintaxe de URL

  • Endereços link-local de IPv6 podem existir no intervalo fe80::whatever em cada interface, então, quando há duas interfaces de rede, é necessário usar scope/zone de IPv6) para distinguir um destino fe80::4
  • O formato do valor de zone varia conforme o sistema operacional: no Linux usa-se o nome da interface, e no Windows o ID da interface
  • No exemplo, eth0 é o nome do dispositivo Ethernet, e o endereço é representado assim
fe80::4%eth0
  • Host e porta normalmente são separados por dois-pontos, mas endereços IPv6 também usam dois-pontos para separar grupos hexadecimais, então fe80::4 com a porta 80 precisa ser envolvido por colchetes da seguinte forma
[fe80::4]:80
  • Ao adicionar a zone, o formato fica assim
[fe80::4%eth0]:80
  • Inserir isso diretamente no host da URL como http://[fe80::4%eth0]:80 falha no net/url do Go, que interpreta %et como um escape de URL inválido
panic: parse "http://[fe80::4%eth0]:80";: invalid URL escape "%et"

Solução segundo o padrão e problemas que ainda restam

  • Valores que não se encaixam na sintaxe de URL devem usar percent-encoding; por exemplo, %20 em uma URL codifica um espaço ASCII, que não é válido diretamente na URL
  • Como o próprio % da zone de IPv6 também precisa ser codificado, em Go é necessário escrever http://[fe80::4%25eth0]:80 para que o resultado de Hostname() seja fe80::4%eth0
  • A RFC 9844 fornece diretrizes para lidar com zone de IPv6 em interfaces de usuário, e a RFC 6874 define a sintaxe de um literal IPv6 com zone em URL da seguinte forma
IP-literal = "[" ( IPv6address / IPv6addrz / IPvFuture  ) "]"

ZoneID = 1*( unreserved / pct-encoded )

IPv6addrz = IPv6address "%25" ZoneID
  • O mesmo caso de borda também aparece no ticket do nginx, na issue do Requests e no rascunho BCP de URI link-local HTTP
  • Navegadores atualmente não oferecem suporte a zone de IPv6, porque isso quebra o conceito de “origin”, usado em muitos comportamentos sutis; esse rascunho tenta definir a origin de zone de IPv6 para que navegadores possam usá-la
  • Para o Anubis apontar para um endereço IPv6 com zone, é preciso aplicar percent-encoding ao %; sob a política de não fazer fork da biblioteca padrão do Go, resta aceitar a UX ruim desse caso de borda

1 comentários

 
GN⁺ 4 시간 전
Comentários do Lobste.rs
  • Uma conclusão no estilo TL;DR: computadores foram um erro parece meio que jogar fora o bebê junto com a água do banho
    Literalmente lembra a lógica de vilão de anime tipo Trigun: como humanos podem cometer crimes horríveis, então deveríamos eliminar todos os humanos
    Sei que é uma frase em tom de brincadeira, mas achei interessante e pretendo usar isso como tema da minha próxima apresentação, que estou preparando agora
    • O título é realmente bem dramático e caça-cliques
      Ainda assim, concordo com o ponto central. Essa situação em si parece bem absurda
  • Não conseguir tratar corretamente endereços IPv6 de escopo link-local em URLs é um erro
    Dito isso, não é exatamente raro que implementações não consigam lidar corretamente com endereços IPv6 link-local
    • Por outro lado, tratar zone em endereços IPv6 dentro de URL aumenta bastante a complexidade
      Agora % passa a ter outro significado apenas na parte de host da URL, e ainda só quando o host é um endereço IPv6 dentro de [...]
      A gramática talvez continue sem ser ambígua, mas esse não é o ponto principal. Quanto mais casos excepcionais assim existirem, maior a chance de um parser de URL deixar passar alguma exceção específica, e diferenças entre parsers facilitam o surgimento de bugs obscuros ou problemas de segurança
      Pessoalmente, prefiro que URLs tratem zone de IPv6, mas como já houve orientação para fazer URL encoding de %, voltar atrás agora realmente cria ambiguidade. É uma pena
  • Bibliotecas ou implementações compatíveis com RFC 3986 vão encontrar esse problema, porque a especificação define sequências percent-encoded assim
    pct-encoded = "%" HEXDIG HEXDIG
    Aqui HEXDIG é definido como [a-fA-F], então %et é interpretado como uma sequência inválida
    A especificação também diz que o caractere % é usado como indicador de um octeto percent-encoded, então, para ser usado como dado dentro de um URI, ele deve ser codificado como %25. Se uma string já decodificada for decodificada de novo, octetos de dados com % podem ser confundidos com o início de percent-encoding; e, se uma string já codificada for codificada de novo, acontece o problema oposto. Por isso, a implementação não deve codificar nem decodificar a mesma string mais de uma vez
    Então, sim, é irritante, mas na prática acho difícil chamar isso de bug
  • Fico pensando por que usar % diretamente em endereços com zone seria algo tão terrível. Caracteres codificados são permitidos também na parte de host, e usar % cru em um endereço com zone realmente cria ambiguidade
    % em si não é um caractere não reservado, então faz sentido aplicar percent-encoding
    Não é nenhuma novidade Go net/url e net/http entrarem em conflito com o RFC de URL. Em especial, a existência de net/url.URL.Path e seu uso em net/http são bem irritantes, porque quebram %2F. net/http.Redirect também usa path.Clean, colapsando // incorretamente para /
    Existem vários motivos para querer fazer fork das partes da biblioteca padrão do Go que mexem com URL ou propor algo como net/url/v2. Mas, pelo que este texto mostra, o tratamento de endereços IPv6 com zone no Go parece razoável e correto