Até um portátil atrás do NAT da operadora pode servir um colega, desde que o servidor VPN funcione como ponto de encontro. Dois mecanismos chegam lá: o cliente liga-se para fora e pede ao servidor que mantenha uma porta à escuta, ou o servidor publica uma porta e tradu-la para dentro do túnel. Ambos resolvem o mesmo problema de alcançabilidade e comportam-se de forma diferente perante falhas, supervisão e registo. Três condições decidem qual pertence à sua instalação.

Duas formas, um ponto de encontro

Na primeira forma o cliente abre uma sessão SSH para fora e pede ao servidor que escute numa porta escolhida, reencaminhando cada ligação por essa sessão. No servidor nada é reencaminhado e não ocorre qualquer tradução de pacotes, pelo que os únicos requisitos são uma conta SSH, um reencaminhamento permitido e uma regra de firewall para a porta. O serviço fica ligado ao loopback no cliente, que costuma ser o pretendido.

ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]

Na segunda forma o servidor é dono da porta pública e reescreve cada ligação para o endereço do túnel do cliente. Isso exige reencaminhamento IP ativo, uma tradução de destino à entrada e uma tradução de origem à saída, e continua a funcionar quando não existe qualquer sessão SSH. A porta pertence ao servidor e não a uma sessão, e é essa propriedade que decide a maioria dos casos reais.

Nenhuma das formas é mais segura por construção. Ambas acabam por expor uma porta de serviço a quem consiga alcançar o endereço público do servidor, e ambas continuam a depender da autenticação do próprio serviço.

Condição um: a porta tem de sobreviver à sessão

Um reencaminhamento inverso vive exatamente o tempo da sessão SSH que o criou. Quando a ligação cai, o ouvinte desaparece e o colega vê uma ligação recusada em vez de um caminho lento. A supervisão do comando com uma unidade systemd e uma política de reinício resolve isso, e ExitOnForwardFailure=yes torna imediatamente visível uma ligação falhada em vez de deixar uma sessão a correr sem reencaminhamento.

Uma porta traduzida sobrevive a reinícios se as regras forem persistidas, mas depende de o cliente manter o mesmo endereço de túnel. Um pool dinâmico que dá ao portátil outro endereço após reconexão aponta a regra silenciosamente para o nada. Reserve primeiro o endereço do túnel, depois escreva a regra, e trate as duas coisas como uma só alteração.

Se o serviço tem de responder às três da manhã sem ninguém a olhar, a forma com a porta publicada pelo servidor tem menos peças móveis, porque o único processo que tem de ficar de pé é o próprio túnel.

Condição dois: a quem pertencem a firewall e os registos

A forma inversa mantém toda a política em dois lugares. sshd decide, através de AllowTcpForwarding, se os reencaminhamentos remotos são permitidos de todo, e GatewayPorts decide se o ouvinte se liga ao loopback ou a todos os endereços. Com o valor predefinido no um colega fora do servidor não alcança a porta mesmo que o reencaminhamento tenha funcionado, e isso parece um túnel avariado quando na verdade é um endereço de ligação.

sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config

A forma traduzida exige reencaminhamento ativo e duas regras, e a segunda regra é onde a maioria das receitas falha. Limitar a tradução de origem ao estado conntrack DNAT significa que só as ligações criadas pela regra de destino são reescritas, em vez de cada pacote que o servidor envia para o túnel.

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1

Essa reescrita também destrói a atribuição. Depois, o cliente vê cada chamador como o endereço do túnel do servidor, o que colapsa qualquer limite de taxa por endereço num único balde e esconde quem enviou o quê. Se a atribuição importa, termine a ligação no servidor ou mantenha aí a decisão de permissão e passe uma identidade num cabeçalho em que o serviço confie. Escolher entre essas duas correções depende de o serviço ler ou não um cabeçalho de proxy.

Condição três: uma porta ou muitas, e a quem pertence o nome

Um único serviço numa única porta é o caso em que o reencaminhamento inverso ganha em esforço. Precisa de um comando, uma conta e uma regra de firewall, e a limpeza é matar a sessão. Vários serviços no mesmo endereço público empurram-no para a forma publicada pelo servidor, porque cada reencaminhamento inverso precisa da sua própria porta de servidor e o conjunto cresce com cada serviço.

Os nomes complicam mais. Um reencaminhamento inverso pode estar atrás de um proxy TCP que encaminha por SNI, enquanto uma porta traduzida é normalmente uma porta por serviço. Se o serviço termina o TLS ele próprio e precisa do nome de anfitrião original, a abordagem por proxy preserva-o e a abordagem DNAT só o preserva se o serviço aceitar esse nome nessa porta.

Anote qual das três condições decidiu a forma. Caso contrário, a próxima pessoa que acrescentar um segundo serviço reabrirá a mesma comparação com menos contexto.

Decida e depois teste a partir de fora

Teste o caminho a partir de uma rede que não tenha qualquer rota até ao portátil, e observe os contadores no servidor enquanto o pedido decorre. Testar do servidor para o seu próprio endereço público não prova nada aqui, porque o pacote é criado localmente e nunca chega ao gancho de tradução de entrada, pelo que o teste pode passar enquanto o caminho real está avariado.

sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20

Contadores que ficam planos significam que o pacote nunca chegou à regra, o que aponta para o fornecedor ou para a firewall do anfitrião. Contadores que se movem enquanto o serviço recusa apontam para a firewall do próprio cliente ou para o endereço onde o serviço escuta. Um túnel que transporta o pacote mas não devolve nada é um problema de rota ou de caminho inverso, e nenhum destes três resultados deve ser depurado editando o adaptador do cliente. Anote que contador se moveu antes de alterar seja o que for, porque o teste seguinte precisa dessa linha de base.

Quando a forma funcionar, registe a porta, o proprietário e o método de supervisão ao lado da configuração do túnel. Uma correção de alcançabilidade que só existe no histórico de shell de alguém está a um reinício de um incidente repetido.

Artigos relacionados