Minha pergunta geral é esta: Qual é a melhor maneira (mais simples, mais fácil, mais rápida, menos propensa a erros, etc.) para verificar as regras NAT do iptables localmente em um único host (ou seja, sem uma conexão de rede) na linha de comando ?
A seguir, os detalhes de tentativas específicas (com falha) de verificar uma regra DNAT simples usando o NetCat. Eu estou esperando por uma resolução do meu problema específico neste caso, mas também por uma resposta à minha pergunta geral.
Estou trabalhando em uma máquina virtual VirtualBox rodando Debian 8 (Jessie). Eu quero usar o netcat para executar um teste básico de uma regra DNAT simples.
Para o meu teste, tudo o que quero fazer é enviar alguns dados para um endereço local (por exemplo, 192.168.0.1
) e fazer com que ele chegue em outro endereço local (por exemplo, 192.168.0.2
).
Já experimentei várias abordagens diferentes:
-
Interfaces fictícias e a cadeia PREROUTING
-
Interfaces virtuais e a cadeia PREROUTING
-
Usando a cadeia OUTPUT em vez de PREROUTING
Interfaces fictícias e a cadeia PREROUTING
Minha primeira tentativa foi adicionar uma regra DNAT à cadeia PREROUTING e adicionar duas interfaces fictícias com os endereços apropriados.
Aqui está minha regra:
sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2
Não existem outras regras do netfilter no meu firewall. Mas só para ter certeza, aqui está a saída de iptables-save
:
# Generated by iptables-save v1.4.21
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 192.168.0.1/32 -j DNAT --to-destination 192.168.0.2
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
Para reiterar, tudo o que quero fazer é enviar alguns dados para o endereço 192.168.0.1
e chegar ao endereço 192.168.0.2
.
Provavelmente vale a pena mencionar que a sub-rede 192.168.0.0/24
não é usada em minha VM. Primeiro, adiciono algumas interfaces fictícias:
sudo ip link add dummy1 type dummy
sudo ip link add dummy2 type dummy
Em seguida, atribuo os endereços IP às interfaces fictícias no intervalo de sub-rede desejado:
sudo ip addr add 192.168.0.1/24 dev dummy1
sudo ip addr add 192.168.0.2/24 dev dummy2
E então eu trago as interfaces para cima:
sudo ip link set dummy1 up
sudo ip link set dummy2 up
Aqui está a aparência da minha tabela de roteamento agora:
default via 10.0.2.2 dev eth0
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
192.168.0.0/24 dev dummy1 proto kernel scope link src 192.168.0.1
192.168.0.0/24 dev dummy2 proto kernel scope link src 192.168.0.2
192.168.56.0/24 dev eth1 proto kernel scope link src 192.168.56.100
Agora eu escuto o primeiro endereço (fonte) usando o netcat:
nc -l -p 1234 -s 192.168.0.1
E eu me conecto ao servidor netcat com um cliente netcat (em uma janela de terminal separada):
nc 192.168.0.1 1234
O texto digitado em uma janela aparece no outro - exatamente como esperado.
Eu também faço o mesmo com o segundo endereço:
nc -l -p 1234 -s 192.168.0.2
nc 192.168.0.2 1234
Mais uma vez, o texto digitado em uma janela aparece no outro - como esperado.
Por fim, tento ouvir o endereço de destino (DNAT) e conectar-me pelo endereço de origem (DNAT):
nc -l -p 1234 -s 192.168.0.2
nc 192.168.0.1 1234
Infelizmente, a conexão falha com o seguinte erro:
(UNKNOWN) [192.168.0.1] 1234 (?) : Connection refused
Eu também tentei usar ping -c 1 -R 192.168.0.1
para ver se o DNAT estava entrando em vigor, mas não parece que é o caso:
PING 192.168.0.1 (192.168.0.1) 56(124) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.047 ms
RR: 192.168.0.1
192.168.0.1
192.168.0.1
192.168.0.1
--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.047/0.047/0.047/0.000 ms
Por que isso não está funcionando? O que estou fazendo errado?
Diagnóstico com o tcpdump
Para diagnosticar esse problema, tentei usar tcpdump
para ouvir o tráfego nas interfaces fictícias. Eu tentei ouvir todas as interfaces (e filtrar SSH e DNS):.
sudo tcpdump -i any -e port not 22 and port not 53
Em seguida, fiz o ping na interface dummy1
:
ping -n -c 1 -I dummy1 192.168.0.1
Isso produziu os seguintes resultados:
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo request, id 8071, seq 1, length 64
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo reply, id 8071, seq 1, length 64
Portanto, parece que as interfaces fictícias estão conectadas à interface de loopback. Isso pode significar que as regras do iptables estão sendo totalmente contornadas.
Interfaces virtuais e a cadeia PREROUTING
Como segunda tentativa, tentei usar os chamados endereços IP virtuais em vez de interfaces fictícias.
Veja como adicionei os endereços IP "virtuais" às interfaces eth0 e eth1:
sudo ip addr add 192.168.0.100/24 dev eth0
sudo ip addr add 192.168.0.101/24 dev eth1
OBSERVAÇÃO: eu usei diferentes endereços IP para eles do que para a interface fictícia.
Então corri e atualizei as regras NAT do iptables:
sudo iptables -F -t nat
sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101
Eu tentei novamente o teste de ping:
ping -n -c 1 -R 192.168.0.100
Sem dados:
PING 192.168.0.100 (192.168.0.100) 56(124) bytes of data.
64 bytes from 192.168.0.100: icmp_seq=1 ttl=64 time=0.023 ms
RR: 192.168.0.100
192.168.0.100
192.168.0.100
192.168.0.100
--- 192.168.0.100 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.023/0.023/0.023/0.000 ms
Em seguida, o teste netcat novamente. Inicie o servidor:
nc -l -p 1234 -s 192.168.0.101
Tente conectar o cliente:
nc 192.168.0.100 1234
Também não há dados:
(UNKNOWN) [192.168.0.100] 1234 (?) : Connection refused
Usando a cadeia OUTPUT em vez de PREROUTING
Então eu tentei mover ambas as regras DNAT da cadeia PREROUTING para a cadeia OUTPUT:
sudo iptables -F -t nat
sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2
sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101
Agora, tento ping nas interfaces fictícias e virtuais:
user@host:~$ ping -c 1 -R 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(124) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.061 ms
RR: 192.168.0.1
192.168.0.2
192.168.0.2
192.168.0.1
--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.061/0.061/0.061/0.000 ms
user@host:~$ ping -c 1 -R 192.168.0.100
PING 192.168.0.100 (192.168.0.100) 56(124) bytes of data.
64 bytes from 192.168.0.100: icmp_seq=1 ttl=64 time=0.058 ms
RR: 192.168.0.100
192.168.0.101
192.168.0.101
192.168.0.100
--- 192.168.0.100 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.058/0.058/0.058/0.000 ms
E também testei o teste cliente-servidor netcat para cada par de endereços IP:
nc -l -p 1234 -s 192.168.0.2
nc 192.168.0.1 1234
e:
nc -l -p 1234 -s 192.168.0.101
nc 192.168.0.100 1234
Este teste também é bem sucedido.
Portanto, parece que as interfaces fictícia e virtual funcionam quando a regra DNAT está na cadeia OUTPUT, em vez da cadeia PREROUTING.
Parece que parte do meu problema é que não estou claro em quais pacotes percorrem as cadeias.