web-dev-qa-db-ja.com

NATおよびポート転送を使用したiptableでの奇妙な動作

複数のデータセンターでホストされている複数の専用サーバーがあり、メールを移行したい(pop3imapsmtpおよびそれらのTLS/SSLバリアント)サービスをあるサーバーから別のサーバーに。

そのために、DNS伝播の時間を処理するために、新しいサーバーから古いサーバーへの[〜#〜] nat [〜#〜]ルーティングを一時的にインストールする予定です。

そこで、次の[〜#〜] iptables [〜#〜]ルールを定義しました:

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 25  -j DNAT --to-destination <my_remote_ip>:8025
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 110 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 143 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 465 -j DNAT --to-destination <my_remote_ip>:8465
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 587 -j DNAT --to-destination <my_remote_ip>:8587
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 993 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 995 -j DNAT --to-destination <my_remote_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 110  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 143  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 993  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 995  -j SNAT --to-source <my_local_ip>
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8025 -j SNAT --to-source <my_local_ip>:25
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8465 -j SNAT --to-source <my_local_ip>:465
iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8587 -j SNAT --to-source <my_local_ip>:587

iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 110  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 143  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 993  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 995  -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8025 -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8465 -j ACCEPT
iptables -A FORWARD -d <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --dport 8587 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 110  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 143  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 993  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 995  -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8025 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8465 -j ACCEPT
iptables -A FORWARD -s <my_remote_ip> -i eth0 -o eth0 -p tcp -m tcp --sport 8587 -j ACCEPT

(実際には単純化されています。実際、これはIPv4とIPV6で重複しており、一部のサーバーではインターフェイスがeth0と異なる場合があります…そしてもちろん実際のIPアドレスを壊しました)

メールサービスはNATのみであることに注意してくださいが、SMTP関連サービスにはポート変換もあり、逆変換またはこれらのポートの特定のリスニングに関連付けられています。宛先サーバー。

それには説得力のある理由があります:私のホスティングプロバイダーは、それらによってホストされているすべてのサーバーでホストされているスパムを検出してブロックするために、発信SMTP接続を監視するために使用します。しかし、SMTPポートへの着信接続を別のサーバーに転送すると、着信スパム発信スパム(fromデータセンターの観点)フィルタリングされる前に(宛先サーバー上)、その結果、ホスティングプロバイダーはすぐにNATサーバーをブロックします。

したがって、これらの接続を転送するには、ポート番号も変換する必要があります。

着信パケットと発信(NAT)パケットは同じインターフェースを使用します(これらのサーバーにはネットワークインターフェースが1つしかないため)

実際には、これは多かれ少なかれ機能しますが、ポート転送接続(とこれらの接続のみ、ポート110、143などでは問題ありません)は奇妙な動作をします:最初に機能します使用している時間ですが、すぐに切断して再接続すると、転送が機能しなくなり、1〜3分待ってから再度接続できるようになります。

これは、ポート番号ではなくIPアドレスに関連しているようです。前の接続がポート110(pop3、ポート転送ではない)であったとしても、ポート25に接続できるようになるまで同じ遅延を待つ必要があります。

いくつかのサーバーで、すべてがLinux Debian WheezyJessie、またはStretchであることを確認しました、およびIPv4IPv6の両方で(NAT IPv6)。 ………はい、Wheezyが古くなったことを知っています。これが、私が移行する理由です。

すべてのIPアドレスは完全に静的です。

はい、/ proc/sys/net/ipv4/ip_forward(およびIPv6と同等)を1に設定しました。

接続のテストにはtelnetを使用し、tcpdumpを使用して転送を確認します。後者を使用すると、転送が実際に行われていないこと、および着信接続をブロックしているのはnot宛先サーバーであることを確認できます。

この1〜3分のブロック遅延の理由と、それを修正する方法を誰かが見つけてくれるでしょうか。

銀杏

1
GingkoFr

あなたの問題は、Linux接続トラッカーの特殊性に関連しています。

簡単な答え:構成でこの遅延を回避することはできません。この問題を回避する唯一の方法は、-j SNATオプションでポート番号を指定せずに--to-sourceを使用することです。

ちょっとしたトリックもありますが、それはほとんど役に立ちません-j SNATで、単一のポート番号の代わりにポートの範囲を使用してください。複数の接続を確立できます。同時接続数は、範囲内のポート数です。ルールは次のようになります。

iptables -t nat -A POSTROUTING -d <my_remote_ip> -p tcp -m tcp --dport 8025 -j SNAT --to-source <my_local_ip>:10025-10125

血まみれの詳細が必要な場合は、答えを拡張できます。

更新

詳細を理解するには、いくつかの背景が必要です。ラミ・ローゼンの"Linux kernel networking: implementation and theory"を読んでください。主に、この本の「第9章Netfilter。接続トラッカー」が必要です。

パケットがLinuxホストを通過すると、Linux接続トラッカー(conntrack)がパケットを分析し、パケットフローに関する情報をテーブル(conntrack table)に格納します。すべてのパケットフローは、conntrackエントリとして表示されます。 conntrackは、タプルを使用してパケットフローを識別します。タプルは、L(両端のIPアドレスとL4プロトコルの数)およびL4(TCPの場合)のポート番号情報です。両端)フローの情報。

Conntrackには、トランスポートプロトコル固有の接続状態をトレースするために、すべてのL4プロトコル用のモジュールがいくつかあります。 TCP conntrack部分は、TCP有限状態マシンを実装します。

ラボ(カーネル4.14)では、このTCP conntrack部分の奇妙な動作があります。これを単純な環境で示しましょう。

クライアント(192.0.2.2)はLinuxホスト(192.0.2.1:22)に接続し、この接続を他のホスト(192.0.2.6:22)に転送します。 Linuxホストも、セットアップと同様にSNATルールを使用します。

Tcpdumpの出力:

14:47:32.036809 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [S], seq 2159011818, win 29200, length 0
14:47:32.037346 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [S.], seq 960236935, ack 2159011819, win 28960, options [mss 1460,sackOK,TS val 1415987649 ecr 3003498128,nop,wscale 5], length 0
14:47:32.037683 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 1, win 913, options [nop,nop,TS val 3003498129 ecr 1415987649], length 0
14:47:32.041407 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [P.], seq 1:22, ack 1, win 905, options [nop,nop,TS val 1415987653 ecr 3003498129], length 21
14:47:32.041806 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 22, win 913, options [nop,nop,TS val 3003498133 ecr 1415987653], length 0
14:47:35.826919 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [F.], seq 1, ack 22, win 913, options [nop,nop,TS val 3003501918 ecr 1415987653], length 0
14:47:35.827996 IP 192.0.2.1.22 > 192.0.2.2.40079: Flags [F.], seq 22, ack 2, win 905, options [nop,nop,TS val 1415991440 ecr 3003501918], length 0
14:47:35.828386 IP 192.0.2.2.40079 > 192.0.2.1.22: Flags [.], ack 23, win 913, options [nop,nop,TS val 3003501919 ecr 1415991440], length 0

Linuxホストのconntrackで、私はこれを見ます:

ipv4     2 tcp      6 431999 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431998 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431997 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 431996 ESTABLISHED src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 119 TIME_WAIT src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2
...
ipv4     2 tcp      6 0 TIME_WAIT src=192.0.2.2 dst=192.0.2.1 sport=40079 dport=22 src=192.0.2.6 dst=192.0.2.5 sport=22 dport=22 [ASSURED] mark=0 zone=0 use=2

ご覧のとおり、接続が正しく閉じられているにもかかわらず、関連付けられたconntrackエントリは、TIME_WAIT状態でconntrackテーブルに表示されます。また、SNATに使用できるポートは1つしかないため、すでにビジー状態であるため、新しい接続の試行は失敗します。なぜこのポートをもう一度使用しないのですか?システムは、192.0.2.6状態の現在のフローと新しいフローの間でTIME_WAITからの応答パケットを区別できないためです。

Conntrackが接続をTIME_WAIT状態に設定し、代わりに私が知らなかった接続を破棄する理由。

3
Anton Danilov