IPv6 link-local não funciona sobre VPN: por que o fe80 para no link
Um endereço fe80:: só tem significado em um link. Veja por que uma VPN roteada não consegue transportá-lo, como a falha aparece e qual endereço usar em vez disso.
Você sobe o túnel, faz ping de fe80::1 com o túnel como interface de origem e nada volta. Não é uma regra de firewall esquecida. Um endereço link-local só tem significado no único link onde foi formado, e uma VPN roteada não é esse link. O fe80::1 do roteador remoto fica no segmento LAN remoto; você está a um salto de distância em outro segmento, e o IPv6 não tem mecanismo algum para um roteador encaminhar pacotes link-local.
O prefixo fe80 descreve um escopo, não uma faixa
Link-local unicast é fe80::/10, e a propriedade que o define não é o número, mas o escopo. O endereço só é válido em um link, e cada interface forma um a partir do próprio identificador, por isso duas máquinas sem relação em duas redes sem relação podem ambas responder a fe80::1 sem o menor conflito. O prefixo basicamente diz “em algum link”; o link em si vem do contexto.
Em um host, esse contexto é a zona, ou scope ID, que você acrescenta depois do sinal de porcentagem: fe80::1%eth0 no Linux, fe80::1%3 ou fe80::1%12 no Windows e em ferramentas que expõem índices de interface. O kernel resolve o endereço junto com o índice da interface e então envia. Remova a zona e o destino fica ambíguo, então a pilha não tem como escolher um segmento.
Por que um túnel roteado não consegue entregá-lo
Uma VPN roteada é uma interface ponto a ponto que carrega os próprios endereços, geralmente um /64 de espaço IPv6 unique-local ou privado dentro do túnel. A LAN remota é um link separado, alcançado pelo endpoint do túnel roteando e encaminhando em seu nome. São dois segmentos distintos, então um endereço de um não é destino válido no outro.
A regra de encaminhamento é explícita no padrão, não uma esquisitice do seu cliente: roteadores não encaminham pacotes com origem ou destino link-local. É por isso que o pacote morre mesmo quando a tabela de rotas parece correta. Adicione uma rota para fe80::/64 apontando para o túnel e uma pilha conforme ou a rejeita ou a aceita e descarta todo pacote correspondente: o escopo do destino diz “apenas este link”, e a interface de saída não é esse link.
A descoberta de vizinhos reforça a mesma fronteira. Hosts resolvem próximos saltos link-local com uma solicitação de vizinho enviada ao multicast de escopo de link com limite de salto 255, então roteadores podem rejeitar tudo o que for encaminhado. Fazer isso funcionar através de um túnel significaria fazer proxy da descoberta para um segmento remoto, o que é uma ponte Layer 2 com outro chapéu.
Há uma segunda falha mais silenciosa, e ela pega quem ainda tenta forçar a rota: a zona. Qualquer zona digitada localmente nomeia a interface do túnel, enquanto o endereço que você quer está vinculado à interface da LAN remota. As duas nunca coincidem, então o pacote não pode ser direcionado para a interface correta na outra ponta.
Como a falha aparece na prática
A saída de ferramentas para um erro de escopo lê como um erro de roteamento ou de firewall, e é exatamente por isso que as pessoas passam uma tarde na camada errada.
| What you run | What you see | What it means |
|---|---|---|
| ping fe80::1 with no zone | Invalid argument on Linux, or a transmit failure on Windows | The stack cannot pick an interface for an ambiguous destination |
| ping -6 -I tun0 fe80::1 | Destination unreachable, or a silent timeout | The address is not on the tunnel link, so there is nothing on-link to answer |
| ssh user@fe80::1 after the tunnel is up | Hangs, then no route to host | The SYN never left the machine in a deliverable form; the server logs nothing |
| ip -6 neigh show dev tun0 | Empty table | No neighbor entry can exist for a link-local host that is not on this link |
| fe80::/64 inside AllowedIPs or route-ipv6 | Config accepted, traffic still dropped | The tunnel carried the packet; the receiving stack refused to forward it |
A terceira linha desperdiça mais tempo, porque um cliente ssh sem saída parece um problema de serviço escutando. Se você tiver qualquer forma de entrar, verifique o lado remoto e confirme se o sshd está ligado a todos os endereços ou só a um.
Use um endereço que foi feito para ser roteado
Para tudo o que você precisa alcançar pelo túnel, use o endereço que o serviço recebeu justamente para isso: um endereço unicast global, ou um endereço unique-local de fc00::/7, a faixa reservada exatamente para este caso interno. Confirme que o ouvinte realmente o vincula, e verifique o caminho de retorno e qualquer regra de firewall do host.
Olhe o host remoto em vez de adivinhar. ip -6 addr show lista os endereços que existem, e ss -6 -ltn lista no que o daemon escuta. Um serviço ligado só a fe80:: é alcançável apenas do próprio segmento, o que costuma ser um padrão que ninguém escolheu de propósito e que pode ser mudado com o acordo do administrador.
Quando o serviço realmente não pode ser religado, suba a ponte para a camada de aplicação em vez da camada de rede. Um relay no host remoto que escuta em um endereço roteável e se conecta ao link-local resolve o problema sem estender segmento algum:
socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80Aqui a zona fica do lado correto, no host que realmente tem eth0 naquele link. Seu cliente fala com fd00:1:2::10, que é roteado normalmente, e o relay faz o salto link-local localmente. O mesmo truque funciona para a interface web de um appliance ou um BMC antigo que só anuncia um endereço link-local.
Quando a ponte é mesmo a resposta, e o que verificar
Algumas implantações realmente precisam de um segmento compartilhado: um dispositivo que só fala descoberta link-local, um appliance que depende de multicast, um laboratório que reproduz uma LAN plana. Isso é um problema de Layer 2 e exige uma resposta de Layer 2, como um dispositivo tap ligado por ponte à interface remota ou um produto cliente com modo de ponte explícito. Isso custa tráfego broadcast e multicast cruzando o túnel mais a descoberta de vizinhos que precisa funcionar de ponta a ponta.
Não chegue perto disso adicionando fe80::/64 a um perfil roteado. Isso produz o pior estado: a configuração parece pronta, a tabela de rotas mostra uma entrada, e todo pacote ainda é descartado em algum lugar entre duas pilhas que ambas se comportam corretamente.
Verifique com a interface em vez do ping. ip -6 addr show tun0 diz se o link do túnel formou um endereço link-local próprio, e ip -6 route get fe80::1%tun0 diz o que o kernel realmente faria com um destino com escopo. Quando o kernel diz que o destino é inalcançável naquela interface, nenhuma configuração de túnel vai mudar isso, e é hora de parar de editar o perfil.
Uma sequência curta que resolve a questão:
- Leia o endereço no host remoto e observe se é fe80:: ou um prefixo roteável.
- Se for fe80::, religue o serviço, faça relay naquele host ou ligue o segmento em ponte; se for roteável, corrija a rota, o firewall ou o endereço de bind.
- Confira a zona toda vez que retestar, porque um comando copiado costuma manter a interface errada.