NAT bidirecional com iptables

NAT bidirecional com iptables

Resumindo, tenho um sistema de cluster em mãos, para o qual preciso rotear o tráfego por meio de seu mestre. O roteamento do tráfego dos nós para o mundo externo funciona, mas o roteamento do tráfego da sub-rede do nosso departamento para os nós falha. Infelizmente, adicionar nós à nossa sub-rede está fora de questão.

A configuração

configuração de cluster, sem switches idiotas para simplificar

O cluster consiste em um mestre e vários nós, juntamente com alguma periferia. Os nós estão em uma rede interna, escondida da nossa intranet ou da internet. Um NAT já está instalado no mestre, portanto os nós têm acesso a servidores internos e externos. Esta parte funciona.

A interface externa do mestre está na mesma sub-rede de nossas estações de trabalho, que compartilham um gateway fora de nosso controle.

Editar: o cluster executa o CentOS 7, os pcs executam uma distribuição baseada no Ubuntu xenial.

A tarefa

Alguns de nossos pacotes de software precisam de acesso direto aos nós. Para isso, queríamos configurar um segundo NAT no master usando iptables, e adicionar uma rota ip nos pcs para enviar tráfego para 10.10.1.0/24 através do master.

A configuração

mestre: rota ip

default via 123.45.67.254 dev eth0 proto static metric 100
10.10.0.0/16 dev eth1 proto kernel scope link src 10.10.0.1
123.45.67.0/23 dev eth0 proto kernel scope link src 123.45.67.204 metric 100

mestre: iptables -vnL -t nat

Chain PREROUTING (policy ACCEPT 7356 packets, 880K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 4884 packets, 687K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 3445 packets, 225K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 3445 packets, 225K bytes)
 pkts bytes target     prot opt in     out     source               destination
  439 33324 MASQUERADE  all  --  *     eth0    10.10.1.0/24         0.0.0.0/0
61828 3710K MASQUERADE  all  --  *     eth1    123.45.67.0/23       10.10.1.0/24

Usar SNAT em vez de MASQUERADE não faz diferença.

nó: rota ip

default via 10.10.0.1 dev eth1
10.10.0.0/16 dev eth1 proto kernel scope link src 10.10.1.1

pc: rota ip

default via 123.45.67.254 dev eth0  proto static  metric 100
10.10.0.0/16 via 123.45.67.204 dev eth0
123.45.67.0/23 dev eth0  proto kernel  scope link  src 123.45.67.191  metric 100

Diagnóstico até agora

  • NAT de node01 para internet/intranet/pcs funciona perfeitamente.
  • NAT de pc1 para node01 falha durante o handshake TCP:
    • SYN é passado pelo master para node01, é marcado como SYN_RECV no tcpdump
    • SYN+ACK é enviado do node01 para o mestre
    • SYN+ACK aparece no tcpdump no master, é passado para filter
    • tcpdump mostra o SYN+ACK passando para filtrar
    • iptables mostra os pacotes SYN+ACK passando pelo filtro FORWARD, mangle FORWARD + POSTROUTING
    • Os pacotes SYN+ACK nunca passam pelo nat POSTROUTING (deveriam?)
    • Os pacotes SYN+ACK nunca chegam ao pc1
  • Claro, o aperto de mão falha
    • pc1 está preso em SYN_SENT
    • node01 está preso em SYN_RECV
    • eventualmente, a conexão expira
  • Não tenho como monitorar pacotes no gateway

Meu melhor palpite é que um roteador stateful no caminho descarta o pacote SYN+ACK devido ao seu endereço de origem ter sido reescrito no mestre, portanto, sua relação com o pacote SYN original é perdida.

Como podemos fazer isso funcionar?

Deixe-me saber se configurações/logs adicionais são necessários.

informação relacionada