
クライアント トラフィックを、 でリッスンしている 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
私はテスト環境を使用しているため、リモート デバイスにアクセスできません。そのため、curl
iptables 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 ルールが一致しなかったためポートは変更されませんでしたが、リモート システムから実行した場合は一致したはずです。
以下の図は、パケットに対して実行される操作の順序を示しています。
その理由は、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 --> ... -->
no
local process receiving on port
8000
ポート 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
およびNATtcpdump
AF_PACKET
これは、上記の図のステップで発生します。入力の場合は非常に早い段階で、出力の場合は非常に遅い段階で発生します。つまり、リモート システムの場合は、動作している場合でもポート 30000 をキャプチャすることはありません。ローカル システムの場合は、nat/OUTPUT
ルールが追加されると、ポート 30000 をキャプチャします。NAT を実行するときに表示されるアドレス/ポートを盲目的に信頼しないでください
tcpdump
。これは、ケースとキャプチャが発生する場所によって異なります。