Encaminhar o tráfego do host por uma VPN numa VM: seis verificações
Seis verificações ordenadas para transformar uma VM no gateway VPN por onde o próprio host encaminha tráfego: modo do adaptador, reencaminhamento, NAT, rotas do host, DNS, MTU.
Seis verificações, executadas por ordem, decidem se uma VM pode servir de gateway VPN ao seu próprio host. O hipervisor não faz nada disto por si: o convidado é dono do túnel, o host é dono de uma rota, e a rede entre eles é encaminhamento comum. Guardo a lista porque saltar um passo produz sempre o mesmo sintoma, silêncio, quando o host faz ping ao convidado alegremente e não chega a nada interno.
Comece pelo motivo. Ou o cliente corporativo só se instala dentro do convidado, ou a política mantém-no lá, e continua a precisar do servidor de compilação interno a partir do host. Se o host puder ter o seu próprio cliente, faça isso: um túnel no host ganha sempre a duas redes mais um NAT.
Verificação 1: o host precisa de uma ligação a que possa dar endereço
O host tem de ter uma interface no mesmo prefixo do segundo adaptador do convidado. Host-only no VirtualBox, host-only ou um VMnet personalizado no VMware Workstation, uma ponte interna ou dispositivo tap no QEMU/KVM e um comutador Internal no Hyper-V qualificam-se todos. Convidado 192.168.56.2, host 192.168.56.1, prefixo 192.168.56.0/24 é a disposição que uso em laboratório.
A rede QEMU em modo de utilizador (-netdev user, o backend SLIRP predefinido) e o NAT do VirtualBox falham esta verificação por completo. Os pacotes do convidado chegam a um processo proxy no host, por isso o host nunca vê um dispositivo que transporte os endereços do convidado e não tem para onde apontar uma rota. O Default Switch do Hyper-V é a mesma história. Se ping 192.168.56.2 a partir do host falhar, pare: nenhuma rota adicionada depois o resolve.
Verificação 2: o convidado reencaminha e traduz
Os pacotes do host chegam com um endereço de origem host-only e um destino interno, por isso o convidado tem de os reencaminhar e depois escondê-los atrás do endereço do seu túnel. Num convidado Linux isso significa reencaminhamento, um par FORWARD accept e source NAT em direção ao túnel:
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -A FORWARD -i eth1 -o tun0 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 192.168.56.0/24 -o tun0 -j MASQUERADE
A regra MASQUERADE é a parte que as pessoas omitem. Os routers corporativos raramente sabem que 192.168.56.0/24 existe; com a regra, os servidores internos veem o endereço do túnel do convidado e respondem-lhe, e a resposta encontra o caminho de volta ao convidado.
Um convidado Windows é mais desajeitado. IPEnableRouter=1 em SYSTEM\CurrentControlSet\Services\Tcpip\Parameters ativa o reencaminhamento sem tradução, por isso só funciona onde o encaminhamento corporativo já aponta de volta para o seu prefixo host-only. A partilha de ligação à Internet traduz, mas renumera o adaptador partilhado para 192.168.137.1, por isso leia o endereço que ele realmente tomou antes de escrever rotas do host.
Verificação 3: as rotas do host nomeiam o convidado, não o túnel
Envie pelo convidado apenas os prefixos de que o host precisa. No Linux basta uma rota por prefixo e ela reverte-se de forma limpa:
sudo ip route add 10.20.0.0/16 via 192.168.56.2
ip route get 10.20.30.40
No Windows o equivalente é route add 10.20.0.0 mask 255.255.0.0 192.168.56.2. Deixe -p de fora enquanto ainda testa, para que uma rota má morra no arranque, e acrescente-o quando o caminho funcionar. Não remova a rota predefinida do host a menos que todas as aplicações do host devam usar o túnel; se o túnel completo for mesmo o requisito, acrescente as duas rotas /1 e mantenha a rota direta para a rede do hipervisor:
sudo ip route add 0.0.0.0/1 via 192.168.56.2
sudo ip route add 128.0.0.0/1 via 192.168.56.2
Num host Windows, verifique também a métrica da interface. Uma rota acrescentada enquanto o adaptador host-only estava desativado fica na tabela mas nunca transporta tráfego, e um segundo adaptador com métrica mais baixa pode ganhar a procura para o mesmo prefixo.
Verificação 4: o DNS segue a rota, não o predefinido do túnel
As rotas movem pacotes; o resolver decide que nomes produzem pacotes. Limite o resolver corporativo à zona corporativa em vez de substituir o resolver do host, e aponte-o para um servidor DNS que a nova rota já alcança. Com systemd-resolved no host:
resolvectl dns eth1 10.20.0.53
resolvectl domain eth1 '~corp.example.com'
No Windows, uma entrada na tabela de políticas de resolução de nomes faz o mesmo trabalho: Add-DnsClientNrptRule -Namespace ".corp.example.com" -NameServers 10.20.0.53. Se o convidado executar o seu próprio resolver no endereço host-only, use esse endereço, mas só depois de confirmar que responde em 192.168.56.2 e não em loopback.
Depois verifique o MTU antes de culpar o DNS por páginas lentas. A interface do túnel é menor do que a interface de 1500 bytes do host, por isso um host que envia segmentos de tamanho completo com o bit DF ligado vê-os cair algures dentro do convidado. O sintoma clássico é um ping a funcionar e uma aplicação web interna que encrava após o handshake TLS. Aperte a MSS no caminho de reencaminhamento do convidado:
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Verificação 5: verifique dos dois extremos
A partir do host, traceroute ou tracert para um endereço interno deve mostrar 192.168.56.2 como primeiro salto, não o gateway físico. No convidado, observe a mesma tentativa a sair: tcpdump -ni any host 10.20.30.40 mostra o pedido reencaminhado do lado host-only e o traduzido no túnel. Um pedido que sai, volta e ainda deixa o host mudo aponta para o caminho de regresso.
Duas falhas explicam a maior parte disso. Ou o túnel do convidado não transporta rota de regresso para o prefixo host-only porque falta a regra NAT, ou a rota do host aponta para um endereço que o convidado já não tem após um reinício. Releia os endereços com ip -br addr e ip route get em vez de confiar em notas da sessão anterior.
Verificação 6: faça-o sobreviver a um reinício e a uma atualização do hipervisor
Torne as duas metades persistentes: configuração de rotas com netplan ou NetworkManager no host, route add ... -p no Windows, e net.ipv4.ip_forward=1 em /etc/sysctl.d/ mais um conjunto de regras de firewall que recarrega no convidado. Tire uma snapshot do convidado assim que a configuração estiver verificada, antes de chegar a próxima atualização do cliente corporativo.
As redes host-only são renumeradas quando um hipervisor recria os seus adaptadores, o que invalida em silêncio cada rota e regra NAT construída sobre 192.168.56.0/24. Após uma atualização, volte a executar as três primeiras verificações por ordem; custa um minuto e apanha o caso em que o host ainda tem a sua rota enquanto o convidado passou para uma nova sub-rede.
O IPv6 exige a sua própria passagem. As regras ip6tables, os registos AAAA e uma segunda família de rotas do host não seguem a configuração IPv4, e um serviço corporativo acessível por IPv6 parecerá permanentemente avariado enquanto o IPv4 funciona.
Passou ou não, por ordem: o host consegue fazer ping ao endereço host-only do convidado; o convidado reencaminha e faz MASQUERADE em direção ao túnel; ip route get devolve o convidado como gateway para o prefixo interno; os nomes corporativos resolvem-se pelo resolver limitado; traceroute mostra o convidado primeiro; e as mesmas seis respostas sobrevivem a um reinício.