Tenho um host1
que possui uma interface WAN eth0
( 1.2.3.4
) e uma interface LAN eth1
( 10.41.82.1
). Dentro da LAN está um host2
com o endereço IP 10.41.82.2
.
As conexões de entrada 1.2.3.4:22
são encaminhadas para host2
usar as seguintes regras do iptables em host1
:
root@host1:~# iptables -t nat -A OUTPUT -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to 10.41.82.2:22
root@host1:~# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to 10.41.82.2:22
Isso funciona bem, exceto quando host2
está tentando acessar 1.2.3.4:22
:
root@host2:~# telnet 1.2.3.4 22
Trying 1.2.3.4...
root@host2:~# ping 1.2.3.4
PING 1.2.3.4 56(84) bytes of data.
64 bytes from 1.2.3.4: icmp_seq=1 ttl=64 time=0.125 ms
64 bytes from 1.2.3.4: icmp_seq=2 ttl=64 time=0.279 ms
root@host2:~# tcptraceroute 1.2.3.4 22
traceroute to 1.2.3.4, 30 hops max, 60 byte packets
1 * * *
2 * * *
3 * * *
4 * * *
5 * * *
(and so on)
Parece que os pacotes estão sendo encaminhados em um círculo. Como você pode ver, o ping funciona, então as rotas e o encaminhamento de IP estão configurados corretamente.
O que fiz de errado e como posso corrigir o problema?
ATUALIZAR:
Conforme mencionado na resposta de BillThor e conforme descrito no tutorial frozentux no DNAT , preciso adicionar uma SNAT
regra. Fiz isso agora (observe que adicionei o endereço LAN de host2
for -d
, pois essa regra é aplicada POSTROUTING
onde o destino do pacote já foi alterado):
root@host1:~# iptables -t nat -A POSTROUTING -d 10.41.82.2 -p tcp --dport 22 -j SNAT --to 10.41.82.1
Infelizmente, isso não resolve o problema e tudo continua igual ao descrito acima. Curiosamente, a SNAT
regra nunca parece ser correspondida, de acordo com os contadores mostrados ao executar iptables -t nat -nvL
.
ATUALIZAÇÃO 2:
Descobri que quando executo tcpdump -i eth1
, mesmo quando executo com parâmetros irrelevantes para este caso, como tcpdump -i eth1 port 34238
, de repente funciona. Mas apenas enquanto tcpdump
está em execução.
O que não mencionei até agora porque achei irrelevante é que eth1
na verdade é uma ponte e host2
é um domínio Xen. Estou começando a suspeitar que meu problema pode estar relacionado a isso.
A razão pela qual falhou está ligada ao fato de que
eth1
é na verdade uma interface de ponte. Na verdade,host2
é uma máquina virtual Xen em execuçãohost1
eeth1
é uma ponte usada para a comunicação entre o host e o convidado.Resolvi o problema ligando
bridge link set dev vif2.0 hairpin on
(ou alternativamentebrctl hairpin eth1 vif2.0 on
).vif2.0
é uma interface de rede virtual criada pelo Xen e faz parte daeth1
ponte.Portanto, para fazer com que o NAT hairpin funcione em uma interface de ponte, certifique-se de ativar o hairpinning da ponte para a interface (que é uma parte da ponte) na qual os pacotes estão chegando.
Adicionar uma
SNAT
regra não foi necessário no final.systemd-networkd
também tem uma diretiva para ativar hairpinning em um arquivo *.network:Eu não tinha certeza se deveria adicioná-lo
eth1.network
ouvif2.0.network
(que normalmente não existe) no meu caso, mas no final nenhum deles funcionou.O que você está tentando fazer é chamado de hairpin NAT. Seria melhor para o host2 apenas se conectar ao host1.
Se você quiser que isso funcione, use SNAT e DNAT para o tráfego originado na rede local indo para o IP externo.
Outra solução que pode funcionar é adicionar uma rota para o host2 ao host1, que direciona o tráfego para o roteador em vez da rede local.