Como encaminhar um aplicativo pela VPN sem a máquina inteira
Nenhum desktop não gerenciado oferece um seletor de VPN por processo. Escolha a camada que seleciona o tráfego: um socket vinculado, uma regra de UID, um perfil de firewall ou um salto SOCKS.
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.
| Mecanismo | O que seleciona | Abrange | Se o túnel cair |
|---|---|---|---|
| Vinculação de socket | endereço de origem | um cliente que você controla | as conexões falham |
| Regra de UID (Linux) | usuário proprietário | todos os processos de uma conta | as conexões falham |
| Perfil de firewall (Windows) | perfil do adaptador | um programa | falha fechado |
| Namespace de rede | associação ao namespace | tudo iniciado dentro dele | as conexões falham |
| Salto SOCKS | configuração de proxy do aplicativo | um aplicativo ou um perfil de navegador | as 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 100Isso 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 443Se 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.