Três hosts Linux, um desenho: um concentrador OpenVPN acessível publicamente, um notebook de consumidor e uma máquina de saída atrás de um roteador doméstico comum que não repassa nada para dentro. A saída marca o concentrador por conta própria. O tráfego de internet do consumidor entra então no túnel no notebook e sai pelo uplink próprio da saída. Tudo o que surpreende nessa disposição decorre de um detalhe: foi a saída que iniciou a conexão, então o caminho para dentro já existe e não é preciso redirecionamento de porta para criá-lo.

O que segue acompanha o caminho do pacote e não a ordem da configuração, porque a configuração só faz sentido quando se sabe qual componente detém qual decisão. Cada camada detém exatamente uma decisão, e os erros se acumulam onde duas camadas são tomadas por uma.

Duas sessões de transporte, um caminho interno

Cada host mantém sua própria conexão externa com o concentrador, e nenhuma dessas conexões sabe da outra. O tráfego do consumidor para a internet é um fluxo interno separado que por acaso é carregado dentro do túnel do consumidor e depois reemitido a partir do túnel da saída. É esse fluxo interno que o concentrador precisa rotear e que a saída precisa repassar.

outer: consumer --TLS--> hub
outer: exit     --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink

Como as duas conexões externas saem do lado do cliente, o roteador da saída nunca vê um SYN de entrada e nunca precisa de uma regra de NAT de destino. Ele só precisa manter vivo o transporte estabelecido, o que já faz para qualquer conexão duradoura. Nada na internet pública precisa alcançar a saída primeiro, por isso um endereço dinâmico nesse uplink não é problema. O roteador ainda precisa permitir a sessão de saída, mas é a mesma permissão que um navegador já usa.

O que o iroute realmente instala dentro do servidor

O concentrador é o único dispositivo que decide qual par possui qual destino, e toma essa decisão na própria tabela de roteamento de espaço de usuário, não na do núcleo. Uma entrada client-config-dir para a saída chamada exit-node pode reivindicar ali o prefixo padrão:

# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0

Essa linha diz ao processo do servidor "pacotes internos com qualquer destino pertencem a este cliente". Ela não adiciona uma rota padrão ao sistema operacional do concentrador nem transforma o concentrador em gateway de internet. Referência do OpenVPN 2.6 mantém o roteamento interno específico do cliente e o roteamento do núcleo como mecanismos separados, e essa separação é a razão pela qual o desenho funciona sem tocar na rota padrão do concentrador.

O consumidor precisa da instrução espelhada, entregue como push, para que o próprio tráfego entre no túnel em vez de sair pelo gateway local. Com topologia de sub-rede, o pool é uma rota conectada no dispositivo tun da saída, então a direção de volta não precisa de push adicional; o que a saída não deve receber é o redirecionamento abaixo, que devolveria o próprio tráfego de uplink ao túnel que ela tenta usar. Envie-o apenas ao consumidor e leia as rotas aplicadas no cliente em vez de confiar que o arquivo CCD foi escolhido.

# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"

O núcleo da saída faz o repasse

Dentro da saída, um pacote do consumidor chega à interface tun endereçado a algum host da internet. O núcleo consulta sua tabela de roteamento, encontra o uplink real como melhor correspondência e então aplica duas políticas independentes: se o pacote pode ser repassado e se pode sair por essa interface com esse endereço de origem. O repasse é um sysctl, e vem desativado por padrão em muitas distribuições.

Assim a saída precisa do repasse IPv4 ativo de forma persistente, de uma regra que admita as origens do túnel do consumidor em direção ao uplink e do caminho de resposta de volta pelo tun. Ativar o repasse para o host inteiro também muda o comportamento de tudo o que é roteado por ele, por isso a regra deveria nomear origens e interfaces em vez de aceitar tudo.

O caminho de volta é comprado pela tradução de origem

Um host da internet não tem rota para um endereço 10.90.0.x, então as respostas seriam descartadas antes de chegar à saída. Reescrever a origem enquanto o pacote deixa o uplink resolve isso, e o rastreamento de conexões desfaz a reescrita na volta.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9   # run on the exit: must point at the tun

A regra acima é um ponto de partida para uma interface de uplink, não uma política de firewall. Estreite a origem para as atribuições que você realmente autorizou e mantenha a política de entrada da própria saída separada, para que o mascaramento do tráfego do túnel não exponha serviços locais em silêncio. Em um host com endereço de uplink dinâmico, o mascaramento também poupa você de acompanhar o endereço à mão.

Onde o concentrador pode impor e onde não pode

Com client-to-client e o caminho de dados tradicional de espaço de usuário, o concentrador entrega pacotes internos entre pares dentro do processo do servidor. Eles nunca atravessam a cadeia FORWARD do núcleo do concentrador, então uma regra do núcleo ali não consegue restringir o trânsito entre pares, por mais cuidadosamente escrita que esteja. A imposição tem de viver na política do próprio servidor: quem pode conectar, qual arquivo CCD recebe e se a propriedade padrão da saída é concedida.

Por isso um iroute padrão é uma decisão ampla de confiança. A saída deve aceitar legitimamente tráfego de volta de endereços de internet arbitrários, e deve ser uma máquina que você controla, corrige e monitora. Dar a mesma propriedade a um par a quem você não entregaria um roteador é o erro a que este desenho convida.

A participação é o controle real. Qualquer cliente que consiga configurar as próprias rotas pode tentar usar a saída, então restringir quem pode conectar, ou a quais pares a saída servirá, faz parte do desenho e não é pensamento posterior.

Falhar com segurança quando a saída desaparece

Desligue a saída e a propriedade padrão interna desaparece com a sessão dela. O que não pode acontecer é o concentrador se tornar em silêncio a saída substituta: nenhuma rota padrão do pool VPN para o uplink do concentrador, e nenhuma regra ampla de mascaramento que repassaria de bom grado o mesmo tráfego. Teste essa falha de propósito e depois teste a recuperação com um fluxo novo e não com uma página que já estava aberta.

# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com

Se o tráfego do consumidor ainda alcança a internet depois que a saída se foi, outra coisa o está transportando e o limite que você pretendia não existe. Trate DNS e IPv6 também como decisões separadas: uma rota IPv4 mais mascaramento não dizem nada sobre tráfego AAAA, e um resolver empurrado pelo concentrador responderá de onde a consulta realmente sai.

Artigos relacionados