Num momento o portátil está na Wi-Fi do escritório, no seguinte está ligado a um telemóvel, e o indicador do túnel volta a estar verde antes de terminares de mudar de janela. A luz verde apenas informa que o túnel se voltou a ligar; o que a política de encaminhamento e bloqueio fez durante o intervalo é outra pergunta. Essa política é um conjunto de condições de correspondência compiladas na última instalação, e nomeia uma interface, um endereço e uma família de endereços que a transição acabou de remover. A mesma mudança produz, por isso, três resultados que parecem idênticos: o bloqueio continua, a política bloqueia a sua própria recuperação, ou abre-se um caminho que nada cobre.

Nada no ecrã separa esses três estados, por isso pergunta a que identificadores as regras estavam presas em vez de que cor mostra o indicador. Em Linux uma regra pode nomear uma interface ou um ipset preenchido a partir dela; em Android pode dizer-se a um VpnService quais as redes subjacentes a seguir através de setUnderlyingNetworks. Cada ligação aponta para um enlace que está prestes a ser substituído, e cada uma tem de ser reavaliada depois.

O que a transição reescreve na realidade

Quando o enlace antigo desaparece, o núcleo remove os seus endereços, retira as rotas que passavam por ele e reconstrói a seleção de endereço de origem com o que resta. A rota predefinida passa para o novo gateway, e o índice de interface a que as regras antigas se referiam desapareceu ou foi reciclado para outro dispositivo. Os resolvers por enlace também são atualizados, embora não no mesmo instante que as rotas. Tudo isto acontece por baixo do cliente VPN, por isso um cliente que só vigia o estado do próprio túnel não vê nada disso.

O problema é que uma regra codifica um identificador concreto em vez da intenção por trás dele. Uma regra que descarta tudo o que não sai pela interface do túnel codifica um nome de interface; uma regra que permite o ponto final codifica um endereço que a nova rede pode encaminhar para outro sítio. Quando o identificador desaparece, a regra não fica visivelmente errada: ou deixa de corresponder a nada ou começa a corresponder à coisa errada.

Reconstruir o túnel exterior sem abrir um buraco

O transporte exterior estava ligado ao endereço de origem antigo, por isso tem de abrir um socket novo a partir do novo. Quando o ponto final é um nome de anfitrião e não um endereço literal, uma consulta tem de ter sucesso enquanto o bloqueio ainda está em vigor. É essa a armadilha da ordem: uma política suficientemente estrita para descartar tudo exceto o ponto final também descartará a consulta necessária para o encontrar, a menos que a resolução aconteça antes de o bloqueio ser levantado ou seja transportada por um túnel ainda vivo. Qualquer das ordens pode funcionar, mas só se o cliente souber em qual está.

Os clientes diferem aqui de uma forma que importa ao diagnosticar. Alguns resolvem primeiro e instalam as regras depois, pelo que uma transição custa uma interrupção visível e depois recupera sozinha; outros mantêm o bloqueio e dependem do túnel sobrevivente para levar a consulta, o que falha por completo quando o túnel morreu com o enlace. Acrescentar uma rota direta predefinida ampla para restaurar a conetividade faz sempre passar o teste e deixa sempre a fuga que estavas a impedir.

Uma rota que ainda aponta para o gateway antigo dá a mesma recuperação encravada por outra causa, por isso lê a tabela antes de culpar o cliente. Os comandos abaixo nomeiam a interface e o endereço de origem que o núcleo usaria de facto, o que resolve numa linha se o caminho antigo ainda está instalado.

ip route get 1.1.1.1
ip -6 route get 2606:4700:4700::1111

Quando o enlace novo traz IPv6 e as regras não

As redes móveis e de convidados distribuem muitas vezes um prefixo IPv6 global mesmo quando a LAN com fios do escritório nunca o fez. Uma política escrita apenas como regras IPv4, a forma predefinida da maioria das receitas feitas à mão de iptables e nftables, não cobre nada disso. O túnel continua ligado, as aplicações com alcance IPv6 saem para fora dele, e o indicador não consegue mostrar a diferença porque o túnel está mesmo ativo. O caso espelho é igualmente comum: um conjunto de regras só para IPv6 não faz nada numa rede que não oferece v6.

Compara o que o enlace oferece com o que a política menciona, nos dois lados da transição. Estes comandos imprimem os mesmos factos com que o cliente trabalha:

ip -4 route show default
ip -6 route show default
sudo nft list ruleset | grep -c 'ip6 '

Se o segundo comando imprimir uma rota predefinida enquanto o terceiro devolve zero, o enlace novo pode fazer sair a máquina por IPv6 sem qualquer regra a vigiá-la. Volta a executar os três depois da mudança, porque o número interessante é a diferença entre as duas execuções. Se o segundo não imprimir nada, aplica-se o caso inverso e qualquer política carregada de v6 ali é só decoração.

O resolver muda de mãos a meio da sessão

Nos sistemas modernos os resolvers estão ligados aos enlaces, por isso um enlace novo chega com um novo conjunto de resolvers e talvez com uma vista split-DNS diferente. O systemd-resolved mantém um âmbito por enlace e escolhe entre eles por rota, enquanto o macOS lê resolvers com âmbito do armazém dinâmico e respeita a ordem das interfaces. Um cliente que instala o seu próprio resolver compete com o do enlace, e as regras de prioridade que ninguém vigia decidem o vencedor. A resolução de nomes pode então quebrar enquanto a filtragem de pacotes faz exatamente aquilo para que foi escrita.

Lê o resolver que está ativo e não o configurado. Num anfitrião systemd o subcomando status mostra de que enlace veio cada âmbito e se está em vigor um nome private-DNS:

resolvectl status --no-pager
resolvectl query intranet.example.com

Se a consulta sai pelo enlace físico em vez do túnel, o cliente perdeu a competição de prioridade e nenhum ajuste de firewall vai corrigir a nomeação. Compara o caminho da consulta nos dois lados da transição para ver qual se moveu. Um nome que resolve para um endereço privado que a rede nova não consegue encaminhar é um terceiro caso, e apresenta-se como tempo limite e não como erro.

Treina a transição e guarda o registo

Reproduz a mudança de propósito em vez de a esperar. Levanta o túnel no primeiro enlace, inicia uma transferência longa e uma consulta repetida, muda depois o enlace e observa qual sobrevive. Anota o intervalo entre o desaparecimento do enlace antigo e o relato do túnel de que está ligado, porque é nessa janela que a política aguentou ou não. Executa a sequência também na outra direção, para que o resultado não seja unilateral.

As exceções precisam do seu próprio passo, porque um desvio justificado na rede antiga não fica justificado automaticamente na nova. Uma impressora, um NAS ou um portal cativo na LAN de casa não têm equivalente na rede móvel, e a exceção que lá chegava torna-se uma regra sem equivalente.

Anota os nomes de interface, as famílias oferecidas, o resolver em vigor e a duração da interrupção para cada direção. Uma religação prova que o transporte recuperou, não que o bloqueio aguentou durante o intervalo, e são afirmações separadas para um bilhete. Com esse registo a transição seguinte é comparada com um estado conhecido e não com a memória.

Artigos relacionados