Tcpdump mostrando porta de redirecionamento diferente após adicionar a regra REDIRECT no iptables

Tcpdump mostrando porta de redirecionamento diferente após adicionar a regra REDIRECT no iptables

Estou tentando direcionar o tráfego do cliente para um cluster Kubernetes NodePort escutando no 192.168.1.100.30000.

O cliente precisa fazer uma solicitação, 192.168.1.100.8000então adicionei a seguinte regra REDIRECT no iptables:

iptables -t nat -I PREROUTING -p tcp --dst 192.168.1.100 --dport 8000 -j REDIRECT --to-port 30000

Em seguida, emito um curl 192.168.1.100:8000, no entanto, no tcpdump vejo uma porta diferente:

# tcpdump -i lo -nnvvv host 192.168.1.100 and port 8000
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
[Interface: lo] 20:39:22.685968 IP (tos 0x0, ttl 64, id 20590, offset 0, flags [DF], proto TCP (6), length 40)
[Interface: lo]     192.168.1.100.8000 > 192.168.1.100.49816: Flags [R.], cksum 0xacda (correct), seq 0, ack 3840205844, win 0, length 0
[Interface: lo] 20:39:37.519256 IP (tos 0x0, ttl 64, id 34221, offset 0, flags [DF], proto TCP (6), length 40)

Eu esperaria que o tcpdump mostrasse algo como

192.168.1.100.8000 > 192.168.1.100.30000

No entanto, ele está sendo exibido e causando um erro de conexão recusada, pois nenhum processo está listado no 192.168.1.100.49816.

192.168.1.100.8000 > 192.168.1.100.49816

Estou usando um ambiente de teste, então não tenho acesso a dispositivos remotos, por isso estou usando curlpara testar o caminho REDIRECT do iptables.

Existe uma razão pela qual adicionar uma regra REDIRECT faz com que o tcpdump redirecione o tráfego para uma porta diferente daquela especificada?

Editar:

Após a sugestão do @AB, adicionei a seguinte regra OUTPUT:

iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000

e curl prossegue, a contagem de pacotes para a cadeia OUTPUT aumenta (embora o pacote da cadeia PREROUTING REDIRECT não tenha aumentado):

2       10   600 REDIRECT   tcp  --  *      *       0.0.0.0/0            192.168.1.100         tcp dpt:8000 redir ports 30000

No entanto, obtendo o seguinte erro:

# curl -vk https://192.168.1.100:8000/v1/api
* About to connect() to 192.168.1.100 port 8000 (#0)
*   Trying 192.168.1.100...
* Connected to 192.168.1.100 (192.168.1.100) port 8000 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12263 (SSL_ERROR_RX_RECORD_TOO_LONG)
* SSL received a record that exceeded the maximum permissible length.
* Closing connection 0
curl: (35) SSL received a record that exceeded the maximum permissible length.

Além disso, tentei adicionar uma rede de sistema remoto, desta vez a contagem de pacotes PREROUTING REDIRECT CHAIN ​​aumenta após a execução remotesystem curl ...(mas a OUTPUT CHAIN ​​não aumenta):

2       34  2040 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.16.128.1         tcp dpt:8000 redir ports 30000

Erro:

# ip netns exec remotesystem curl -vk https://192.168.1.100:8000/v1/api
* About to connect() to 192.168.1.100 port 8000 (#0)
*   Trying 192.168.1.100...
* Connection timed out
* Failed connect to 192.168.1.100:8000; Connection timed out
* Closing connection 0
curl: (7) Failed connect to 192.168.1.100:8000; Connection timed out

Responder1

Para ser claro: o teste do OP é feito do sistema 192.168.1.100 para ele mesmo, não de um sistema remoto, e essa é a causa do problema. A porta não foi alterada neste caso porque nenhuma regra NAT correspondeu, embora teria correspondido se fosse feita a partir de um sistema remoto.

O esquema abaixo mostra como a ordem das operações é executada em um pacote:

Fluxo de pacotes no Netfilter e na rede geral

A razão é como o NAT funciona no Linux:tabelas de ipvê um pacote na nattabela apenas para o primeiro pacote de um novo fluxo conntrack (que está, portanto, no estado NEW).

Esta regra funciona bem quando proveniente de um sistema remoto. Neste caso, o primeiro pacote visto será um pacote recebido:

to port 8000 --> AF_PACKET (tcpdump) --> conntrack --> nat/PREROUTING (iptables REDIRECT): to port 30000
--> routing decision --> ... --> local process receiving on port 30000

Todos os pacotes seguintes no mesmo fluxo terão conntrack manipulando diretamente a mudança de porta (ou reversão de porta para respostas) e pularão qualquer regra iptables na nattabela (conforme escrito no esquema: nattabela consultada apenas para NEWconexões). Então, (pulando a parte do pacote de resposta), o próximo pacote recebido passará por isso:

to port 8000 --> AF_PACKET (tcpdump) --> conntrack: to port 30000
--> routing decision --> ... --> local process receiving on port 30000

Para um teste do próprio sistema, o primeiro pacote não é um pacote de entrada, mas um pacote de saída. Em vez disso, isso acontece usando a lointerface de saída:

local process client curl --> routing decision --> conntrack --> nat/OUTPUT (no rule here)
--> reroute check --> AF_PACKET (tcpdump) --> to port 8000

E agora esse pacote é retornado na lointerface, ele reaparece como um pacote que não é mais o primeiro pacote em uma conexão, então segue o segundo caso acima: conntrack sozinho cuida do NAT e não chama nat/PREROUTING. Exceto que não foi instruído na etapa anterior para fazer nenhum NAT:

to port 8000 --> AF_PACKET (tcpdump) --> conntrack
--> routing decision --> ... -->nolocal process receiving on port8000

como não há nada escutando na porta 8000, o sistema operacional envia de volta um TCP RST.

Para que isso funcione no sistema local, uma REDIRECTregra também deve ser colocada na nat/OUTPUTcadeia:

iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000

Notas Adicionais

  • se o caso for para uso remoto, não teste no sistema local: as regras percorridas pelo teste não são as mesmas. Isso faz com que o teste não reflita a realidade.

    Basta usar um namespace de rede para criar um sistema remoto de bolso caso nenhum outro sistema esteja disponível. Exemplo que deve funcionar com um sistema tendo apenas nat/PREROUTINGregras e ações do OP curl http://192.168.1.100/(que não requer DNS):

    ip netns add remotesystem
    ip link add name vethremote up type veth peer netns remotesystem name eth0
    ip address add 192.0.2.1/24 dev vethremote
    ip -n remotesystem address add 192.0.2.2/24 dev eth0
    ip -n remotesystem link set eth0 up
    ip -n remotesystem route add 192.168.1.100 via 192.0.2.1
    ip netns exec remotesystem curl http://192.168.1.100:8000/
    
  • tcpdumpe NAT

    tcpdumpacontece nas AF_PACKETetapas do esquema acima: muito cedo para entrada e muito tarde para saída. Isso significa que para um caso de sistema remoto, ele nunca capturará a porta 30000 mesmo quando estiver funcionando. Para o caso do sistema local, uma vez nat/OUTPUTadicionada a regra, ela capturará a porta 30000.

    Só não confie cegamente no endereço/porta exibido ao tcpdumpfazer NAT: depende do caso e de onde acontece a captura.

informação relacionada