O cliente de VPN se conecta, o navegador funciona e o único comando que você realmente quer continua saindo pela sua conexão doméstica. Ou acontece o contrário: o túnel assume a rota padrão e o servidor de arquivos local desaparece da área de trabalho. Eu enfrentei isso com um agente de build que precisava alcançar um espelho interno de artefatos enquanto o resto da máquina permanecia na LAN do escritório, e o cliente oferecia exatamente duas opções, todo o tráfego ou nenhum. O pedido dos dois lados é o mesmo, este programa e não a máquina inteira, e a maioria dos clientes não tem essa caixa de seleção, porque a tabela de rotas nunca soube o que é um programa.

Por que a tabela de rotas não consegue ver o seu programa

Quando um processo envia um pacote, a pilha consulta o endereço de destino na tabela de rotas. Nem o nome do executável nem a porta entram nessa consulta. Os nomes de domínio falham pelo mesmo motivo: um túnel conduz o tráfego até um endereço, e quando um nome é resolvido para um endereço, o roteamento é a única alavanca que o kernel ainda tem. É por isso que "VPN apenas para este site" acaba significando um proxy, e "VPN apenas para este programa" acaba significando um de um pequeno conjunto de mecanismos.

MecanismoO que selecionaAbrangeSe o túnel cair
Vinculação de socketendereço de origemum cliente que você controlaas conexões falham
Regra de UID (Linux)usuário proprietáriotodos os processos de uma contaas conexões falham
Perfil de firewall (Windows)perfil do adaptadorum programafalha fechado
Namespace de redeassociação ao namespacetudo iniciado dentro deleas conexões falham
Salto SOCKSconfiguração de proxy do aplicativoum aplicativo ou um perfil de navegadoras conexões falham

Nenhum deles é uma rota por processo. Cada um desloca a decisão para uma camada que consegue ver o programa, o usuário ou a configuração do próprio aplicativo.

Um único destino ainda é uma rota, não uma regra por programa. No macOS, a receita usual é desmarcar "Enviar todo o tráfego pela VPN" e adicionar uma rota de host: sudo route add -host internal-tuner.example -interface ppp0, removida de novo com sudo route delete -host internal-tuner.example -interface ppp0. Leia o nome da interface em ifconfig primeiro, já que ppp0 é apenas um exemplo. Curingas não funcionam em uma rota de host, então um serviço que fala com vários nomes precisa de uma entrada por nome, e a regra cobre todos os processos da máquina, não apenas aquele que você tinha em mente.

Vincule o socket ao endereço do túnel

Quando você controla o cliente, a vinculação é o seletor mais barato. Um socket vinculado ao endereço local do túnel sai por essa interface desde que exista ali uma rota para o destino, e todo o resto da máquina mantém o caminho normal. A sutileza é que a vinculação escolhe o endereço de origem enquanto a tabela de rotas continua escolhendo a saída. A vinculação sozinha não move para o túnel o tráfego que não tem rota, e é esse o erro por trás da maioria dos relatos do tipo "vinculei e ainda sai pelo caminho errado".

import socket
s = socket.socket()
s.bind(("10.8.0.2", 0))
s.connect(("build.internal.example", 443))

Ferramentas de nível mais alto expõem a mesma ideia: curl --interface 10.8.0.2, o CURLOPT_INTERFACE do PHP e o argumento source_address nos clientes HTTP do Python. O endereço tem de pertencer ao túnel, e um erro de digitação aqui falha como um erro comum de conexão, não como uma queixa de roteamento. Vincular a um nome de dispositivo em vez de um endereço é um privilégio do Linux e não se transporta para Windows ou macOS, e é por isso que scripts portáveis passam o endereço.

Linux: combine com o proprietário, não com o nome do programa

O kernel consegue comparar o usuário proprietário de um socket, então uma conta dedicada se torna o seletor. Coloque o túnel na própria tabela de rotas e envie só o tráfego dessa conta para lá:

ip rule add uidrange 1001-1001 lookup 100
ip route add default dev tun0 table 100

Isso só funciona se o túnel ainda não for a rota padrão. Inicie o cliente com --route-nopull, ou filtre o redirecionamento empurrado com --pull-filter ignore "redirect-gateway" no OpenVPN 2.4 e posteriores, e depois adicione você mesmo a entrada da tabela. Caso contrário, os dois padrões existem e o de menor prioridade vence. A versão deliberada disso é apontar a rota padrão para o gateway do túnel, ou fazê-lo a partir de um script de desconexão: mantém o tráfego fora da internet quando o túnel cai, mas isso é um kill switch, não um seletor, e permanece até alguém removê-lo.

A versão mais forte é um namespace de rede. Crie-o, execute o cliente dentro dele e inicie a aplicação com ip netns exec. Nada fora do namespace vê a interface do túnel, então a aplicação não pode voltar acidentalmente para a rota do host. O custo é real: o namespace precisa de um par veth para alcançar a rede física e do próprio arquivo de resolução, porque o namespace de montagem não compartilha as configurações de resolução do host.

Dois modos de falha explicam a maioria dos vazamentos. A resolução de nomes continua acontecendo no resolvedor do host, então a consulta sai fora do túnel mesmo quando a conexão TCP vai por dentro. E o IPv6 precisa da própria ip -6 rule, porque uma regra v4 não o cobre.

Windows e macOS: restrinja o firewall ou entregue um proxy

O Windows também não tem um seletor de rota por aplicativo, mas as regras de firewall podem ser restritas a um perfil, e um adaptador de VPN pode ser classificado como Público enquanto a LAN doméstica continua Privada. Crie regras de bloqueio de saída para o programa nos perfis Privado e Domínio, deixe o Público aberto, e a aplicação só poderá alcançar a rede pelo túnel. Defina primeiro a categoria de rede da conexão e depois confirme no painel de monitoramento do firewall que a regra foi aplicada. É um bloqueio, não uma rota: falha fechado quando o túnel cai, e não consegue impedir uma aplicação que ignore o firewall.

O macOS segue a mesma lógica com ferramentas diferentes. Um ouvinte SOCKS alcançado por SSH é a opção menos invasiva, já que ssh -D 1080 user@host cria uma porta local e só os aplicativos configurados para usá-la seguem esse caminho. Uma regra pf pode bloquear um programa por usuário ou grupo, mas ainda não consegue escolher o túnel só para esse programa. O Tunnelblick não consegue filtrar por domínio de forma alguma, porque as rotas trabalham com endereços; usuários do OpenConnect recorrem ao vpn-slice quando o servidor empurra uma lista de prefixos ampla demais.

Dois contornos cobrem o que as ferramentas da plataforma não fazem. Extensões de navegador que trocam de proxy por domínio são a resposta prática para "apenas este site", porque atuam na camada de aplicação, onde os nomes ainda existem; cobrem um navegador e nada mais. O contorno grosseiro é executar o cliente do fornecedor dentro de uma máquina virtual, para que o convidado assuma a mudança de rota enquanto o host mantém o caminho, ao custo de duas pilhas de rede para manter.

Um salto SOCKS para ferramentas sem opção de vinculação

A maioria dos aplicativos pode ser apontada para um proxy HTTP ou SOCKS mesmo quando não sabe nada sobre interfaces. Um cliente SSH fornece um sem nenhuma mudança no servidor:

ssh -N -D 127.0.0.1:9999 [email protected]

Tudo o que estiver configurado para usar essa porta sai pelo bastião enquanto o resto da área de trabalho mantém a conexão normal. Uma instância local do 3proxy vinculada ao endereço do túnel faz o mesmo para uma porta sem SSH, e o stunnel cobre uma única porta envolvida em TLS. Os limites são práticos: um proxy só transporta protocolos que sabem usá-lo, o UDP precisa da associação UDP do SOCKS5 que a configuração "SOCKS5" de muitos clientes não habilita, e o DNS precisa ser resolvido pelo proxy (socks5h no curl) ou o nome vaza para o resolvedor local.

Mantenha o ouvinte em loopback a menos que outra máquina precise dele.

Verifique o caminho com uma captura, não com uma mensagem de status

As janelas de status do aplicativo descrevem a configuração, não o pacote. Capture nas duas interfaces e compare:

tcpdump -i any -n port 443
ss -tnp | grep 443

Se a conexão aparece na interface física sem entrada correspondente no túnel, o seletor não está em vigor, independentemente do que o cliente relata. Verifique o IPv6 e o resolvedor separadamente, e procure um segundo caminho, como um processo auxiliar ou um proxy de sistema herdado.

Depois escolha a fronteira que corresponde ao requisito: um proxy basta para um site, uma regra de UID basta para uma conta, um perfil de firewall basta quando a conexão precisa falhar fechada, e um namespace é a única opção que esconde o túnel de tudo o que está fora dele.

Artigos relacionados