Uma rota de saída desta estação de trabalho é um proxy SOCKS, e o OpenVPN atrás dele relata tempo limite de conexão sem nenhum detalhe útil. O navegador na mesma máquina funciona por esse proxy, as credenciais estão certas e a porta responde. Três coisas diferem com frequência suficiente para serem verificadas primeiro: a versão SOCKS que o proxy fala, o transporte que o cliente escolheu e o local onde ocorre a resolução de nomes. Confirme cada uma antes de culpar o firewall.

Alinhe a versão SOCKS antes do firewall

O OpenVPN da comunidade fala SOCKS5 para socks-proxy. Aponte-o para um proxy que só oferece SOCKS4 e a conexão TCP abre e trava, porque o cliente espera resposta a uma saudação que o outro lado nunca analisa. De fora, essa parada parece exatamente uma porta filtrada, por isso a questão da versão vem antes de qualquer regra de firewall. Uma busca com conhecimento de SOCKS resolve isso com um comando.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example

Uma requisição concluída prova duas coisas ao mesmo tempo: o proxy aceitou a requisição SOCKS e resolveu o nome. Não é preciso esquema de URL, porque o curl trata um host puro como HTTP, e isso basta para este teste.

Essa busca também descarta a falha que o log do cliente esconde. O proxy pode permitir o navegador e ainda recusar o destino VPN, e nesse caso a recusa acontece no CONNECT, antes de qualquer autenticação VPN. O OpenVPN relata apenas tempo limite, então a resposta do próprio proxy é a evidência que você precisa.

O transporte tem de ser TCP dos dois lados

O SOCKS5 carrega um fluxo TCP aqui, então o próprio túnel precisa de proto tcp-client. Um perfil ainda configurado para UDP não vai funcionar por esse caminho, porque o cliente não usa o modo de associação UDP do protocolo. Inverter o perfil é uma mudança real, não uma formalidade: o lado remoto precisa escutar TCP na mesma porta. Depois a carga passa a ser TCP dentro de TCP, onde um segmento perdido é retransmitido duas vezes e o ritmo piora, o que sessões interativas notam bem mais que transferências grandes.

proto tcp-client
remote gw.lab.example 8443
socks-proxy 127.0.0.1 9050

A diretiva recebe o host do proxy, uma porta opcional e um arquivo de credenciais opcional. Coloque-os no próprio perfil para que uma cópia se comporte igual em outro lugar.

Encerre a cadeia inteira num único contêiner

Fazer a cadeia no host significa assumir a rota padrão dele e deixar o resolvedor num estado que ninguém vai explicar depois. Um namespace ou contêiner a delimita em vez disso, então o host mantém o próprio caminho enquanto o salto SOCKS e o túnel vivem juntos. Nada sobe lá dentro sem dispositivo de túnel, direitos para configurá-lo e um proxy alcançável. Um serviço Compose consegue isso com cap_add: NET_ADMIN e um /dev/net/tun montado por bind.

cap_add:
  - NET_ADMIN
devices:
  - /dev/net/tun:/dev/net/tun

Esse par é mais estreito do que rodar o contêiner privilegiado, e é todo o acesso ao dispositivo necessário. Um cliente Tor ou um contêiner de proxy separado pode fornecer o ouvinte. Nos dois casos amarre-o ao loopback e alcance-o a partir do namespace pelo host, em vez de expor o proxy à rede.

A resolução de nomes é onde o isolamento falha

Um túnel que carrega pacotes mas pergunta ao resolvedor do host não isolou nada. Duas coisas tornam o isolamento real: o namespace tem resolvedor próprio, e as consultas dele passam pelo proxy ou pelo túnel, nunca pela interface física. Use dois nomes no teste: um que só existe atrás do túnel e um público que deveria seguir o mesmo caminho.

docker compose exec vpn cat /etc/resolv.conf
docker compose exec vpn getent hosts internal.lab.example

Se o nome remoto resolve e o público não, a cadeia é seletiva e não quebrada, e a diferença diz qual caminho cada consulta tomou. Se ambos resolvem a partir do host mas nenhum dentro do contêiner, o contêiner ainda está tomando emprestado o resolvedor do host. Anote o arquivo de resolvedor que encontrou, porque é essa configuração que precisa mudar.

Prove cada salto em ordem

A lista é curta. Uma requisição SOCKS5 recebe resposta, o túnel chega ao seu ouvinte pelo proxy e os pacotes que deixam o namespace carregam o endereço que o lado remoto espera. Confirme um de cada vez em vez de empilhar mais configuração. Quando o cliente diz conectado e nada se move, a quebra está quase sempre no segundo ou no terceiro fato.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example
docker compose exec vpn ip route get 203.0.113.10
docker compose exec vpn getent hosts internal.lab.example

Anote a combinação que funcionou: versão SOCKS, transporte, resolvedor e configurações de namespace. Resolver esta cadeia uma segunda vez de memória custa mais do que a nota. Mantenha esses quatro fatos no ticket e não no chat.

Uma cadeia que relata conectado e não passa nada costuma ter falhado no salto que você ainda não provou. Teste esse salto antes de acrescentar outra camada.

Artigos relacionados