現時点では、LinuxのNetfilterアーキテクチャの詳細について説明しています。私はすでにNetfilterフック、テーブル、チェーン、さまざまなカーネルモジュールなどに精通しています。
しかし、理解できない接続追跡と組み合わせたNATの1つの詳細があります。
私は小さなSNATの例で問題を説明しようとしています。この例では、問題を理解する必要がないため、トランスポート層は無視します。間違いがあったら訂正してください!
ローカルネットワークには、IPアドレス192.168.2.55のクライアントコンピュータと、外部IPアドレス193.157.56.3のNATゲートウェイがあります。これで、クライアントはサーバーおよびインターネット上のIPアドレス217.254.1.76と通信したいと考えています。
そのため、クライアントはsrc = 192.168.2.55/dst = 217.254.1.76のパケットを、デフォルトゲートウェイでもあるNATゲートウェイに送信します。接続追跡はこの新しい接続を追跡し、2つの新しいタプルを作成します。
IP_CT_DIR_ORIGINAL:src = 192.168.2.55、dst = 217.254.1.76
IP_CT_DIR_REPLY:src = 217.254.1.76、dst = 192.168.2.55
IP_CT_DIR_ORIGINALおよびIP_CT_DIR_REPLYは、2つのタプルの配列にアクセスするためのマクロです。
POSTROUTINGフックでNATは既存の接続の接続追跡を要求し、これが成功した場合、パケットのヘッダーの送信元アドレスを変更します。また、宛先を元に戻すためのDNATルールをサイレントに作成します返信アドレス。
これで問題が発生しました。 NATは、IP_CT_DIR_REPLYの宛先アドレスをその外部IPアドレス193.157.56.3に変更します。したがって、タプルは次のようになります。
IP_CT_DIR_ORIGINAL:src = 192.168.2.55、dst = 217.254.1.76
IP_CT_DIR_REPLY:src = 217.254.1.76、dst = 193.157.56.3
そのため、応答用の既存のタプルがあるため、接続追跡はPREROUTINGフックで応答を追跡できます。しかし、パケットを追跡した後NATは宛先アドレスをクライアントのアドレス192.168.2.55に変更します。
今私の質問:接続追跡はどのようにPOSTROUTINGフックでこのパケットを追跡できますか? NATにより変更されたため、src = 217.254.1.76/dst = 192.168.2.55の応答タプルはありません。
見逃したことはありますか?
http://conntrack-tools.netfilter.org/ から、通常conntrackまたはconntrack-toolsとしてパッケージ化されているconntrack
コマンドをインストールする必要があります。ほとんどの場合、/proc/net/nf_conntrack
と同じコンテンツが表示されますが、さらに多くのことができます。
NATゲートウェイ:conntrack -E
(またはconntrack -E --proto tcp --orig-port-dst 443
を選択してHTTPSに制限することができます)でイベントモードでconntrackを実行します。今、HTTPSリクエストを使用する前の例では、これに似たもの:
[NEW] tcp 6 120 SYN_SENT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 [UNREPLIED] src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798
[UPDATE] tcp 6 60 SYN_RECV src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798
[UPDATE] tcp 6 432000 ESTABLISHED src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[UPDATE] tcp 6 120 FIN_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[UPDATE] tcp 6 60 CLOSE_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[UPDATE] tcp 6 30 LAST_ACK src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[UPDATE] tcp 6 120 TIME_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[DESTROY] tcp 6 src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
Natテーブルは特別です。つまり、 使用されるonlyフローごとに1回 *、[NEW]
状態が作成されました。その他はすべて、見つかったconntrackエントリによって短絡されます。 POSTROUTINGのSNATルールは、応答に対して「サイレントにDNATルールを作成」しませんでした。これはconntrackエントリを変更して、dst = 193.157.56.3と応答し、netfilterに「何かを変更しました」と伝えました。それ以外のすべて(ソースIPの変更を含む)は、iptablesではなく、conntrack(モジュールnf_conntrack、nf_conntrack_ipv4)とnat(モジュールnf_nat、nf_nat_ipv4、およびおそらくさらにいくつか)によって処理されます。エントリが接続状態データベースであると考えます。
応答パケットが受信されると、関連付けが保存されていないパケットはconntrackエントリを介して調べられます(実際には、元の部分または応答部分のどちらかで関連付けを調べますが、これは問題ではありません)。エントリは以前に作成されたため、一致が見つかりました。次に、パックされた情報がこの接続の関連付けで更新されます。プロパティの一部(ソースまたは宛先...)が変更された場合でも、エントリを後で検索する必要はありません。情報は直接利用できます。これを処理するマクロ/インライン関数のいくつかは skbuff.h で定義されています。 _nfct
およびnfct
を探します。パケット(別名skbuff)は、ルックアップ後、この値をskb->_nfct
で受け取ります。
それで、あなたが見逃したかもしれないいくつかのこと:
-m conntrack --ctstate ESTABLISHED
)またはnat(natテーブル内のすべてのもの)のリソースを使用できます。上記の例では、conntrackエントリのみがパケットを「de-SNAT」するための情報を持っています。実際、これは、元々着信接続のあるDNATに似ています。数回iptables-save -c
を実行してnatテーブルのルールのカウンターがどのように増加するかを見ると、最初のパケットのみについて、natテーブルが最初のパケット以降に他のパケットを認識していないと確信できます。
* NATの部分を見てください:
このテーブルは、新しい接続の最初のパケットのみがテーブルを通過するという点で、「filter」テーブルとは少し異なります。この走査の結果は、同じ接続の将来のすべてのパケットに適用されます。