O seu serviço funciona na máquina, o túnel está de pé e, mesmo assim, o navegador na sua secretária continua à espera de resposta. Nada está avariado no sentido habitual: a aplicação escuta dentro de um espaço de nomes de rede, e essa pilha é invisível para a LAN. O seu loopback pertence ao espaço de nomes, por isso um cliente noutra máquina não tem qualquer endereço que chegue à porta. Um salto deliberado, ou um par veth, resolve isso sem mover o resto do host.

Porque nada responde no endereço da LAN

Um espaço de nomes é uma pilha de rede completa: interfaces, rotas, regras de firewall e um loopback privado. Um processo lançado através de ip netns exec vê essa pilha e nada mais, por isso o endereço a que se liga só é resolvido dentro do espaço de nomes. O próprio 127.0.0.1 do host é um loopback completamente diferente.

É por isso que o curl no host falha enquanto o mesmo comando dentro do espaço de nomes tem sucesso. A aplicação está saudável; o endereço simplesmente não existe na pilha do host.

Publicar uma só porta com um salto socat

socat faz a ponte entre as duas pilhas no espaço do utilizador, o que basta quando é uma única porta TCP que tem de atravessar. O lado do host escuta na LAN e, para cada ligação aceite, inicia um segundo socat dentro do espaço de nomes que se liga ao loopback da aplicação. O processo interno chega à aplicação exatamente como um cliente local faria. Nada no encaminhamento do espaço de nomes muda, por isso a aplicação continua a usar o túnel como única saída.

socat TCP-LISTEN:9100,reuseaddr,fork EXEC:'ip netns exec vpn socat STDIO tcp-connect:127.0.0.1:9100',nofork

O processo externo precisa de root ou da capacidade de entrar no espaço de nomes. Se a VPN cair, a aplicação perde o caminho e a porta publicada falha fechada, que é o comportamento que se quer de uma jaula.

Usar um par veth quando atravessa mais de uma porta

Um par veth é a resposta certa quando têm de atravessar várias portas ou protocolos, ou quando outros hosts precisam de iniciar ligações. Uma extremidade fica no host, a outra passa para o espaço de nomes, e um /30 pequeno dá aos dois lados um endereço estável. Depois uma rota do host envia o endereço do espaço de nomes pelo par.

ip link add veth0 type veth peer name veth1
ip link set veth1 netns vpn
ip addr add 10.77.0.1/30 dev veth0
ip link set veth0 up
ip netns exec vpn ip addr add 10.77.0.2/30 dev veth1
ip netns exec vpn ip link set veth1 up

Não acrescente uma rota predefinida através do host a menos que queira quebrar a jaula. O túnel deve continuar a ser a saída, por isso pelo par só é acessível o endereço do serviço publicado. Dê também ao espaço de nomes o seu próprio ficheiro de resolução, porque ip netns exec lê /etc/netns/vpn/resolv.conf e sem ele a resolução de nomes dentro da jaula fica vazia.

Testar a partir de outra máquina, não do host

Faça o teste a partir de uma segunda máquina, porque o host consegue chegar a um listener local por caminhos que não dizem nada sobre a LAN. Verifique primeiro a que a aplicação se ligou realmente dentro do espaço de nomes e só depois ligue-se de fora ao endereço publicado. Ligar-se a todos os endereços ali não alarga a jaula, porque o curinga continua a pertencer ao espaço de nomes e a LAN não o consegue ver.

ip netns exec vpn ss -lntp

Se a ligação a partir do host funcionar e a da LAN não, a peça em falta é o salto ou a rota, não o endereço de ligação. Inicie o OpenVPN dentro do espaço de nomes em vez de mover para lá um dispositivo tun ativo, porque mover a interface desliga-a e pode limpar rotas que depois não conseguirá reparar de fora. Mantenha os comandos de recuperação na consola, não dentro da jaula.

Artigos relacionados