iptables に REDIRECT ルールを追加した後、tcpdump が異なるリダイレクト ポートを表示する

iptables に REDIRECT ルールを追加した後、tcpdump が異なるリダイレクト ポートを表示する

クライアント トラフィックを、 でリッスンしている Kubernetes クラスター NodePort に送信しようとしています192.168.1.100.30000

クライアントはリクエストを行う必要がある192.168.1.100.8000ため、iptables に次の REDIRECT ルールを追加しました。

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

次に curl を発行します192.168.1.100:8000が、tcpdump では別のポートが表示されます。

# 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)

tcpdumpには次のような内容が表示されるはずです

192.168.1.100.8000 > 192.168.1.100.30000

ただし、プロセスがリストされていないため、接続拒否エラーが表示され、発生しています192.168.1.100.49816

192.168.1.100.8000 > 192.168.1.100.49816

私はテスト環境を使用しているため、リモート デバイスにアクセスできません。そのため、curliptables REDIRECT パスをテストするために を使用しています。

REDIRECT ルールを追加すると、tcpdump がトラフィックを指定されたポートとは別のポートにリダイレクトする理由はありますか?

編集:

@AB の提案に従って、次の OUTPUT ルールを追加しました:

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

curl がさらに進むと、OUTPUT チェーンのパケット数が増加します (ただし、PREROUTING REDIRECT チェーンのパケットは増加しません)。

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

ただし、次のエラーが発生します。

# 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.

また、リモートシステム ネットを追加してみましたが、今回は実行後に PREROUTING REDIRECT CHAIN パケット数が増加しますremotesystem curl ...(ただし、OUTPUT CHAIN は増加しません)。

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

エラー:

# 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

答え1

明確に言うと、OP のテストはリモート システムからではなく、システム 192.168.1.100 からそれ自体に対して実行されており、これが問題の原因です。この場合、NAT ルールが一致しなかったためポートは変更されませんでしたが、リモート システムから実行した場合は一致したはずです。

以下の図は、パケットに対して実行される操作の順序を示しています。

Netfilter と一般的なネットワークにおけるパケットフロー

その理由は、Linux 上で NAT がどのように動作するかにあります。iptablesnat新しい conntrack フローの最初のパケット (したがって NEW 状態) についてのみ、テーブル内のパケットを確認します。

このルールはリモート システムからの場合は正常に機能します。この場合、最初に確認されるパケットは着信パケットになります。

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

同じフロー内の後続のすべてのパケットでは、conntrack がポート変更 (または応答のポートの復帰) を直接処理し、テーブル内の iptables ルールをスキップしますnat(図に書かれているように、natテーブルは接続に対してのみ参照されますNEW)。したがって、(応答パケット部分をスキップして) 次の着信パケットは代わりに次の処理を受けます。

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

システム自体のテストの場合、最初のパケットは着信パケットではなく発信パケットです。代わりに、発信loインターフェイスを使用して次の処理が行われます。

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

そして、このパケットはloインターフェース上でループバックされ、接続の最初のパケットではなくなったパケットとして再び表示されるため、上記の 2 番目のケースに従います。つまり、conntrack のみが NAT を処理し、呼び出しませんnat/PREROUTING。ただし、前の手順で NAT を実行するように指示されていません。

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

ポート 8000 でリッスンしているものが何もないため、OS は TCP RST を返します。

これをローカル システムで機能させるには、チェーンREDIRECTにルールも追加する必要がありますnat/OUTPUT

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

その他の注意事項

  • ケースがリモート使用を目的としている場合は、ローカル システムからテストしないでください。テストによって走査されるルールは同じではありません。これにより、テストが現実を反映しなくなります。

    nat/PREROUTING他のシステムが利用できない場合に備えて、ネットワーク名前空間を使用してポケット リモート システムを作成します。これは、OP のルールのみを持ち、次の操作を実行するシステムで動作するはずですcurl http://192.168.1.100/(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/
    
  • tcpdumpおよびNAT

    tcpdumpAF_PACKETこれは、上記の図のステップで発生します。入力の場合は非常に早い段階で、出力の場合は非常に遅い段階で発生します。つまり、リモート システムの場合は、動作している場合でもポート 30000 をキャプチャすることはありません。ローカル システムの場合は、nat/OUTPUTルールが追加されると、ポート 30000 をキャプチャします。

    NAT を実行するときに表示されるアドレス/ポートを盲目的に信頼しないでくださいtcpdump。これは、ケースとキャプチャが発生する場所によって異なります。

関連情報