Android always-on VPN: como o nome do endpoint é resolvido primeiro
O Android bloqueia o tráfego antes de o túnel existir, mas o cliente ainda precisa resolver o próprio endpoint. Aqui está a ordem, e onde isso trava.
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.
| Stage | Who resolves | Path | Failure looks like |
|---|---|---|---|
| Endpoint lookup | The VPN app | Underlying network, protected socket | Never connects; no tunnel interface traffic |
| Peer authentication | Client and server | Tunnel transport | Connects then drops; certificate or key error |
| Private name lookup | Apps via the tunnel | Resolver inside the tun | Tunnel 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.