O telefone reinicia, o always-on está ativo, «bloquear conexões sem VPN» está ligado, e o túnel nunca sobe. Nada está mal configurado: o bloqueio faz o seu trabalho, e a própria tentativa do cliente de alcançar o seu endpoint está sujeita a ele. O nome do endpoint precisa ser resolvido antes de o túnel existir, por um cliente a quem é permitido falar com a rede enquanto todos os outros aplicativos não podem. Entender qual componente faz isso, e em que ordem, é o que transforma este mistério numa questão de configuração.

O que o builder de VPN realmente pede

Um aplicativo VPN Android não entrega ao sistema o endereço de um servidor. Ele constrói uma interface local: endereços e rotas para o túnel, os resolvedores que os aplicativos devem usar dentro dele, e então establish() devolve um descritor de arquivo que o aplicativo lê e escreve como pacotes IP brutos. O endpoint remoto não aparece nesse builder de forma alguma.

Esse é o fato estrutural central. A plataforma cria uma interface tun e aplica políticas sobre ela; o aplicativo implementa o transporte no espaço do usuário, o que significa que é o próprio aplicativo que resolve o nome do seu endpoint e abre a conexão criptografada. Um endpoint na forma de nome de host é, portanto, possível — não porque a plataforma suporte nomes, mas porque a plataforma nunca vê o endpoint.

Um campo do builder aceita endereços: os servidores DNS. Eles precisam ser endereços numéricos de resolvedores, normalmente os que o operador quer consultar através do túnel. Esse campo descreve para onde os aplicativos enviam consultas depois que o túnel está de pé. Ele não diz nada sobre como o cliente encontra o endpoint, e tratar os dois como a mesma configuração é onde a confusão começa.

Duas perguntas de DNS, não uma

A primeira pergunta é: para onde os aplicativos enviam consultas quando o túnel está de pé? A resposta é um endereço de resolvedor dentro do túnel, alcançável pela interface tun, e numérico por construção.

A segunda pergunta é: como o cliente encontra o seu próprio endpoint antes de esse túnel existir? Essa busca acontece fora do túnel, na rede subjacente, no processo do cliente. Ela pode usar um nome, e precisa usar um resolvedor que o dispositivo alcance sem VPN.

StageWho resolvesPathFailure looks like
Endpoint lookupThe VPN appUnderlying network, protected socketNever connects; no tunnel interface traffic
Peer authenticationClient and serverTunnel transportConnects then drops; certificate or key error
Private name lookupApps via the tunnelResolver inside the tunTunnel up, internal sites do not resolve

Três estágios, três sintomas diferentes. Uma única mensagem de erro dizendo «não é possível conectar» junta todos eles, e é por isso que as pessoas acabam editando o campo de servidor DNS para corrigir um problema que ocorre antes de esse campo ser sequer consultado.

Por que o bootstrap pode travar

Always-on com o bloqueio ativo significa que o tráfego que não está dentro da VPN é descartado, incluindo o tráfego do aplicativo que é dono da VPN. A saída é explícita: o aplicativo chama protect() num socket, o que o liga à rede subjacente, de modo que ele contorna o túnel e tem permissão para sair. Todo cliente VPN precisa fazer isso para o seu próprio transporte, ou nunca alcançaria um servidor.

Considere agora uma implantação em que o único resolvedor que conhece o nome do endpoint está ele mesmo dentro do túnel. O cliente precisa do túnel para resolver o nome, e do nome para construir o túnel. É uma dependência circular real, e nenhuma configuração de cliente a resolve. É um erro de projeto, não um bug.

O tempo expõe a mesma dependência de formas mais brandas. Ao iniciar, antes do primeiro desbloqueio, o dispositivo pode ainda não ter uma rede utilizável; num captive portal a rede existe, mas bloqueia tudo exceto o portal; na transição de Wi-Fi para celular, a rede subjacente do socket protegido muda e o cliente precisa notar isso e resolver de novo. Cada uma dessas é um evento de bootstrap, e cada uma merece ser testada de propósito em vez de descoberta às 3 da manhã.

Por que fixar a resposta não é uma solução

O atalho tentador é resolver o nome uma vez e colar o endereço resultante num campo numérico, ou codificá-lo numa build personalizada. Parece funcionar, e transforma um nome numa fotografia. Quando o operador move o endpoint — uma migração, uma mudança de anycast, um novo endereço regional — o cliente continua discando o antigo e nada na interface explica por quê.

Os registros DNS têm um tempo de vida justamente para que as respostas possam mudar; o cache é definido em termos desse tempo de vida, não para sempre. Fixar uma resposta descarta o mecanismo que torna um nome melhor que um endereço, mantendo o custo operacional de ter usado um nome.

Fixar a resposta também costuma andar junto com um segundo hábito ruim: afrouxar as verificações de identidade porque a conexão agora falha de outra forma. A verificação da identidade do servidor não faz parte do problema de bootstrap, e enfraquecê-la troca um incômodo de DNS por um risco de interceptação.

Projetos que sobrevivem a um reinício

O arranjo durável não tem glamour. Use um cliente que implemente sockets protegidos corretamente e resolva o seu endpoint na rede subjacente, e dê a ele um nome de endpoint que resolva publicamente, ou através de um resolvedor alcançável antes do túnel. Mantenha o bloqueio ativo; desativá-lo por completo para fazer o DNS funcionar remove a propriedade para a qual a implantação existe.

Onde o endpoint precisa permanecer privado, forneça um caminho de bootstrap explícito que a plataforma possa usar — um resolvedor alcançável sem o túnel, ou uma conexão de gerenciamento mantida pelo operador — e mantenha essa exceção estreita e pertencente à política, não a um botão do usuário. A documentação do Android VpnService é a referência para o que a plataforma garante sobre proteção e ciclo de vida, e a referência do VpnService.Builder confirma que o campo DNS aceita endereços numéricos.

Depois verifique os três estágios, na ordem, numa conexão nova após um reinício: o nome do endpoint é resolvido, o túnel é estabelecido e o par é autenticado, e um nome privado é resolvido pelo resolvedor do túnel. Se o primeiro estágio falhar, nada depois pode funcionar, e a correção pertence ao caminho de bootstrap — nunca ao campo de resolvedor.

  • A resolução do endpoint acontece no aplicativo, fora do túnel, num socket protegido.
  • O campo DNS do builder é para os aplicativos dentro do túnel, não para o endpoint do próprio cliente.
  • Um resolvedor alcançável apenas pelo túnel é um travamento, não um início lento.
  • Teste endpoint, autenticação e consulta privada separadamente após um reinício.

Artigos relacionados