- 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
Comentários do Lobste.rs
TL;DR: computadores foram um erroparece meio que jogar fora o bebê junto com a água do banhoLiteralmente 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
Ainda assim, concordo com o ponto central. Essa situação em si parece bem absurda
Dito isso, não é exatamente raro que implementações não consigam lidar corretamente com endereços IPv6 link-local
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 penapct-encoded = "%" HEXDIG HEXDIGAqui
HEXDIGé definido como[a-fA-F], então%eté interpretado como uma sequência inválidaA 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 vezEntão, sim, é irritante, mas na prática acho difícil chamar isso de bug
%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-encodingNão é nenhuma novidade Go
net/urlenet/httpentrarem em conflito com o RFC de URL. Em especial, a existência denet/url.URL.Pathe seu uso emnet/httpsão bem irritantes, porque quebram%2F.net/http.Redirecttambém usapath.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