Android chroot VPN: por que o túnel funciona e os apps o ignoram
O chroot muda apenas a busca de caminhos, não o kernel, o namespace de rede ou o registro de VPN do Android. Daí decorrem dois resultados, e ambos surpreendem as pessoas.
Você põe uma distribuição Linux rodando sob chroot no celular, instala um cliente VPN dentro dela, e o shell anuncia que o túnel está pronto. Depois você passa para o navegador e o tráfego sai pelos dados móveis como se nada tivesse acontecido. Ou o contrário: todo app do celular perde conectividade porque o cliente instalou uma rota padrão no namespace que o Android realmente usa. Os dois sintomas vêm da mesma peça que falta, e nenhum deles é um bug do cliente VPN.
O shell diz conectado, os apps discordam
O primeiro resultado é o comum. Um túnel de espaço de usuário aberto a partir do chroot pode concluir o handshake, imprimir as estatísticas e carregar o tráfego que o próprio shell gera, enquanto os apps do Android continuam usando a rede padrão do celular. Nada os intercepta, porque nada disse ao Android que existe uma VPN.
O segundo resultado é o perigoso. Se o chroot compartilha o namespace de rede do Android, o que faz por padrão, um processo com privilégios suficientes pode adicionar rotas e uma interface TUN que afetam o celular inteiro. Aí o túnel funciona para todo app, inclusive os que você não pretendia rotear, e a conectividade do celular passa a depender de um daemon sem gestão de ciclo de vida, sem indicador de conexão e sem política de sempre ativo.
Qual dos dois você obteve dá para responder com um comando. Compare ip route dentro do chroot com o mesmo comando em um shell do Android fora dele. Saída idêntica significa que o chroot está no namespace do host: qualquer mudança de rede que ele faça vale para o celular inteiro. Saída diferente significa que o launcher criou um namespace para ele, e o túnel dele é invisível ao Android por construção.
O que o chroot mudou e o que não mudou
| Object | Effect of a chroot |
|---|---|
| Pathname resolution | Changed: lookups start at the new root |
| Kernel and drivers | Unchanged: the phone's kernel, its TUN driver, its limits |
| Network namespace | Unchanged unless the launcher creates one |
| Android VPN registration | Unchanged: no app consented, no VPN is selected |
A chamada de sistema chroot faz uma coisa: muda o diretório usado na resolução de nomes de caminho. A página man é explícita ao dizer que não é uma fronteira de segurança, e não diz nada sobre interfaces, rotas ou estado de VPN. Tudo o que as pessoas esperam de um contêiner Linux — pilha de rede privada, sistema de arquivos filtrado, limites de recursos — vem de outros mecanismos que o launcher pode ou não ter usado.
É por isso que afirmações de que o chroot isola uma VPN normalmente respondem à pergunta errada. A pergunta relevante é em que namespace o processo roda e a que domínio SELinux ele está restrito, e ambos são propriedades de como ele foi iniciado, não da palavra chroot.
TUN precisa de três coisas, e um nó de dispositivo é só uma
Um túnel tradicional de espaço de usuário precisa de um dispositivo TUN que possa abrir, suporte do kernel para esse dispositivo e permissão para configurar a interface e as rotas. São requisitos separados, e criar um nome de caminho sob /dev não satisfaz nenhum deles por si só:
ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun
No Android o kernel costuma ter suporte a TUN compilado, porque o próprio serviço de VPN da plataforma o usa, mas isso não significa que seu processo possa usá-lo. A configuração da interface exige a capacidade de administração de rede, e o SELinux decide se o processo pode sequer alcançar o nó do dispositivo. Uma negação parece um erro de permissão sem causa óbvia, e a resposta está no registro de auditoria:
dmesg | grep avc
logcat -d | grep "avc: denied"
Root não resolve isso. O SELinux restringe processos rodando como uid 0 exatamente como restringe os outros, então um chroot iniciado a partir de um shell root ainda pode ser negado a um dispositivo que enxerga. Desligar a aplicação da política para fazer um instalador antigo funcionar é uma decisão para o celular inteiro, com consequências muito além do túnel, e não é correção para um binário obsoleto.
Por que os apps do Android ignoram seu túnel
O modelo suportado do Android é um app de VPN que se registra pelo serviço de VPN da plataforma, pede o consentimento do usuário uma vez e recebe um descritor de arquivo para o túnel. A plataforma então encaminha o tráfego para esse descritor e aplica o escopo de apps que o usuário ou o administrador escolheu, e por isso o mesmo mecanismo pode ser por app, por perfil e combinado com ajustes de sempre ativo e bloquear sem VPN. O guia de desenvolvimento de VPN do Android descreve esse handshake, e o ponto central é que é um registro, não um truque de roteamento.
Um daemon dentro do chroot nunca se registra. Não há diálogo de consentimento, nem ícone de chave na barra de status, nem lista de inclusão ou exclusão por app, e nenhuma participação na política de sempre ativo. Por isso os apps continuam usando a rede padrão, e o túnel carrega apenas o que o próprio shell envia.
Ir pelo outro caminho também não ajuda. Empurrar rotas para o namespace do host captura tudo, inclusive tráfego que a plataforma esperava manter local, e isso sem controle por app e sem forma de o usuário ver ou revogar. Não existe ajuste intermediário em que um daemon do chroot roteie tráfego para um único app.
Compatibilidade binária é um muro à parte
Mesmo quando o lado de rede é interessante, o executável tem requisitos próprios: arquitetura de CPU, o carregador dinâmico, a biblioteca C e os recursos de kernel que espera. O Android usa bionic em vez de glibc, e um binário antigo compilado para uma distribuição de desktop pode precisar de bibliotecas que não existem mais no aparelho.
Ligar o nome de um arquivo de biblioteca a uma versão mais nova por link simbólico não cria compatibilidade ABI, e uma biblioteca criptográfica arquivada de um pacote de dez anos atrás não é um componente mantido. Se o plano depende disso, o plano é rodar código sem manutenção com privilégios de rede em um celular.
Prove no contexto do Android e limpe depois
Teste o que de fato importa para você, pelo lado que interessa: abra o app específico, alcance o destino privado específico, confirme qual resolver respondeu, então desconecte o túnel e confirme o comportamento documentado. Um resultado de um terminal dentro do chroot é evidência sobre o contexto de execução daquele terminal e nada mais.
Se você mudou rotas do host durante os experimentos, reverta-as e registre o que mudou. Depois verifique se o celular tem uma VPN de sempre ativo configurada, porque um experimento antigo que deixou uma regra para trás pode parecer falha da plataforma meses depois.
Para uma necessidade real de acesso remoto, use o cliente suportado do serviço ou um desenho de gateway aprovado. A pergunta que vale fazer não é se dá para fazer um instalador com root rodar, mas se uma implementação suportada leva os apps de que você precisa pela fronteira que você pretendia, sem deixar mudanças privilegiadas sem dono no aparelho.