web-dev-qa-db-ja.com

LinuxはACKの解釈に失敗し、SYN + ACKを再送信し続けます

以下は、発生している問題のwiresharkダンプであり、IPアドレスは「client」と「server」に置き換えられています。

4414.229553  client -> server TCP 62464 > http [SYN] Seq=0 Win=65535 Len=0 MSS=1452 WS=3 TSV=116730231 TSER=0
4414.229633 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406364374 TSER=116730231 WS=6
4414.263330  client -> server TCP 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730231 TSER=2406364374
4418.812859 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406365520 TSER=116730231 WS=6
4418.892176  client -> server TCP [TCP Dup ACK 778#1] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730278 TSER=2406365520
4424.812864 server -> client  TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406367020 TSER=116730278 WS=6
4424.891240  client -> server TCP [TCP Dup ACK 778#2] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730337 TSER=2406367020

したがって、サーバーがACKを解釈していないように見えることを除いて、通常のSYN、SYN + ACK、ACKシーケンスが発生しているように見えます。代わりに、SYN + ACKを再送信し続けます。これは、クライアントが前のACKの複製で忠実に応答し続けます。これがどのように起こるのかわかりません。

Iptables接続追跡はこれらの接続が確立されたと見なし、120時間のタイムアウトの間、それらをメモリに保持するため、問題に気づきました。実際に多くの接続をアクティブにすることなく、制限に達した多数の同時接続を防ぐためのファイアウォールルールがいくつかあります。 netstatコマンドは、これらのファントム接続を表示しません。

他の情報:

サーバーは、ストックカーネルを備えた標準のDebianLennyシステムです。

Linux tb 2.6.26-2-686 #1 SMP Wed Aug 19 06:06:52 UTC 2009 i686 GNU/Linux

ランニング:

Apache/2.2.9 (Debian) mod_ssl/2.2.9 OpenSSL/0.9.8g

クライアントにすべての情報がありません(ローカルで再現できません)が、Chromeブラウザを実行しているMacです。

ACKパケットをいじるファイアウォールルールはありません。基本的に私はSYNパケットのみをフィルタリングし、他のすべてのTCPパケットは通過を許可されます。したがって、同時接続のカウントとTCP確立パケットのグラフ化以外は、実際にはファイアウォールの接続追跡を使用しません。他のパケットタイプと比較して。

編集:私のiptables-TCPポート80に関連するルール:

iptables -P INPUT ACCEPT
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 -j LOGDROP-CONN
iptables -A INPUT -p tcp --syn -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p tcp --syn -j REJECT --reject-with tcp-reset
iptables -A LOGDROP-CONN -m limit --limit 1/minute --limit-burst 1 -j LOG --log-prefix "ConConn "
iptables -A LOGDROP-CONN -j DROP

編集2:今度はtcpdump -vvを使用して別のダンプ:

16:05:52.999525 IP (tos 0x0, ttl 55, id 46466, offset 0, flags [DF], proto TCP (6), length 64) client.50538 > server.www: S, cksum 0x4429 (correct), 38417001:38417001(0) win 65535 <mss 1452,nop,wscale 3,nop,nop,timestamp 117224762 0,sackOK,eol>
16:05:52.999580 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0xa2ab (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418739698 117224762,nop,wscale 6>
16:05:53.321788 IP (tos 0x0, ttl 55, id 24299, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe813 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224765 2418739698>
16:05:56.252697 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0x9f7a (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418740512 117224765,nop,wscale 6>
16:05:56.277250 IP (tos 0x0, ttl 55, id 15533, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe4c4 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224798 2418740512>
5

総当たり攻撃します。まず、iptablesを停止して動作するかどうか試してみます。もしそうなら、それはiptablesの何かです。

次に、ルールを1つずつ追加し、どのルールが接続障害の原因になるかを監視します。次に、トラフィックを完全に中断することなく、必要な処理が実行されるまで、そのルールを試してみました。

Iptablesを停止しても機能しない場合は、非常に奇妙になり始めます。

2
Paweł Brodacki

わかりました。完全な答えはありませんが、この問題が最初に発生して以来、多くのことを学びました。ここで私の洞察を共有します。

  • まず、問題はGoogle Chromeで開いたウェブサイトにいくつかのソケット(私のテストでは6つ)を開くことによって引き起こされました。これは、ウェブサイトのさまざまな要素のダウンロードを開始するために行われます。並列。私のように多くのアイテムがない単純なWebサイトの場合、これらの事前に開いたソケットの一部はアイドル状態になります。他の最新のブラウザーでもこれを行うことを読みました。
  • 接続追跡の問題を引き起こしているクライアントは、ホームルーターなどが壊れている可能性があります。アイドル状態のソケットは、FINまたはRSTパケットを送信して破棄せずに消える傾向があるためです。
  • SYN + ACKパケットの繰り返しは正常なようですTCP動作、パケットダンプを実行してからtelnet www.website.com 80やテストしたサーバーはすべてLinuxを実行している可能性があるため、データを送信しません。この動作はiptables-rulesがロードされていない場合にも発生するため、実際にはカーネルに関連しています。
  • 応答なしでいくつかのSYN + ACKパケットを送信した後、Linuxカーネルは接続の側を切断します。 iptables connection-trackingはこのロジックを共有していないようです。そのため、接続はタイムアウトするまでESTABLISHED状態のままになります。これのデフォルトのタイムアウトは5日(!)です。これを数時間など、もっと賢明なものに減らすことを計画しています。
  • ACKを受信した後にSYN + ACKを繰り返すことは、完全にデフォルトの動作ではありません。nc -l ###でリスニングポートを開いてそれに接続したときに表示されなかったためです。したがって、Apacheがリスニングソケットに設定する特定のTCPオプションである可能性があります。または、Apacheに完全に固有のものである可能性があります。他のほとんどのデーモンは、接続直後にアナウンスするため、有効なテストケースではありません。このため、接続は3ウェイハンドシェイクを実行し、すぐにアイドル状態になる必要があります。

しかし、上記の洞察に感謝しますが、それらはこれの根底に到達するのに役立ちました。

0