web-dev-qa-db-ja.com

Linux:netstat -s「失敗した接続試行」のソースの追跡

複数のサーバーがあり、netstat -s(/ proc/net/snmpから)によって返される失敗した接続試行のメトリックが1秒あたり約1つ増加しているため、これらの原因を診断したいと思います。

このipTablesルールを使用して(別のサーバーで):

-A出力-p tcp --dport 23 -j REJECT

発信Telnetをブロックしているので、次のループを実行できます。

trueの間;行う
telnet www.google.co.uk
netstat -s | grep「接続に失敗しました」
完了

209.85.203.94を試行しています...
telnet:リモートホストに接続できません:接続が拒否されました
52回の接続試行失敗
209.85.203.94を試行しています... telnet:リモートホストに接続できません:接続が拒否されました
53回の接続試行の失敗
209.85.203.94を試行しています... telnet:リモートホストに接続できません:接続が拒否されました
54回の接続試行の失敗

したがって、リモートソケットへの接続の試行が失敗すると、カウンタが増加することを証明します。 (もちろん、それが増加の唯一の原因であることは証明していません)。

問題は、次のステップを確認するために、失敗しているリモートアドレスとポート(または両方の複数)の特定の組み合わせをどのように見つけられるかです。ルーティング/ファイアウォールの問題?
余談ですが、これを実行すると:

ウォッチ-n1の| grep "\ <23 \>" '

ソケットがSYN-SENT状態になることを期待していましたが、そうではありません。これは、DROPではなくREJECTを使用したためですか?ありがとう

5
Graham Nicholls

別の方法(難しい方法)で質問に答えてみましょう。カーネルのソースを読んで、このメトリックが増加する場所が1つだけあることを確認します- tcp_done 関数。コードからわかるように、増分はSYN_SENDまたはSYN_RECV状態の接続でのみ発生します。次に、tcp_doneを呼び出すことができる場所を確認します。そして私たちはいくつかの場所を見つけることができます:

  1. tcp_reset -接続の中止時に呼び出されます(最初のフラグを受け取ったパケットに応答します)。うん、それはSYN_SENTとSYN_RECVの状態(そして理論的には他の状態)で起こります。
  2. tcp_rcv_state_process -状態TCP_FIN_WAIT1およびTCP_LAST_ACKで呼び出されるため、メトリックは増分されません-それは私たちのケースではありません。
  3. tcp_v4_error -SYN_SENTまたはSYN_RECVの場合に呼び出されます。 ICMPハンドラーによって呼び出されるtcp_v4_error関数。
  4. tcp_time_wait -ソケットをtime-waitまたはfin-wait-2状態に移行するときに呼び出されます-私たちの場合もそうではありません。
  5. tcp_write_error -タイムアウト時にいくつかの場所から呼び出され、再送信カウントを超えました。それも私たちの容疑者になることができます。

ここで、TCP FSMダイアグラムを開いて確認します。どのような場合に、接続がSYN_SENTまたはSYN_RECVにあるかを確認します。

クライアントの場合は、SYN_SENT状態のみであり、synパケットが送信されており、リジェクト(tcp-rstまたはicmpエラー)を受信したために接続が中止されたか、応答が受信されません。

サーバーの場合は、SYN_RECV状態(synがすでに受信され、syn + ackがすでに送信されている)であり、リジェクト(syn + ackがどこかでリジェクト)を受信したために接続が打ち切られたか、応答待機タイムアウトを超えた(ackはない)受け取った)。

これで、このメトリックが更新される理由がわかり、システムでそのメトリックの考えられるソースを確認できます。最新のカーネルには、カーネルレベルでトラブルシューティングを行うための強力なツールがあります。 この簡単なチュートリアル から始めて、Brendan Greggから。

2
Anton Danilov

いったん切断された接続の重要な原因は、応答しないサーバーに接続しようとする試みであると思われます。 「接続試行の失敗」とは、発信接続を指すと考えています。

ランニング

ss | awk '$ 1〜/ SYN-SENT/{print $ NF}'

10.160.32.211:8312
10.160.33.61:8312
10.160.32.146:8312
10.160.33.216:8312
10.160.34.186:8312
10.160.35.18:8312
10.160.32.157:8312
10.160.33.159:8312
10.160.34.246:8312

この状態の多くの接続を示します。興味深いことに、それはそれらすべてが同じポートに接続しようとしていることを示しています。そのリストからランダムなIPアドレスを試し、telnetでポート8312に接続しようとすると、次のようになります。

$ telnet 10.160.34.246 8312
telnet:アドレス10.160.32.48に接続:接続がタイムアウトしました

SYNパケットの送信は、接続を確立するための最初のステップです。反対側はSYN-ACKパケットで応答する必要があります。この場合、ACKで応答し、接続が確立されます。ただし、2つのサーバー間にファイアウォールがあり、接続がブロックされている場合は、SYN-ACKが送信されないため、ソケットはタイムアウトするまでSYN_SENT状態のままになります。
lwn.netから盗んだ図は次のとおりです。

Diagram of TCP 3-way handshake

このタイムアウトは長くありません(私はどのくらいの時間を見つけようとしており、適切に更新します)-これまでのところ知ることができる限り、それは数秒のオーダーです(MSLが2倍になると思っていましたが、MSLはは最大セグメント存続期間ですが、それは推測です)。

ここで、SYNが送信され何も返されない接続試行と、RSTが返される接続試行を区別する必要があります。途中のファイアウォールは、通常、かなり失礼です。元のSYNパケットをサイレントにドロップします。RSTを送信しません。これは、ここに何もないことをクライアントに通知する通常の方法です。

同様の動作は、www.google.co.ukにリッスンしないと思われるポートで接続しようとすると表示されます-例:

$ telnet www.google.co.uk 32654
74.125.203.94を試行しています... telnet:アドレス74.125.203.94に接続:接続がタイムアウトしました

同時に次のようなものを実行している間:

trueの間; ssを行う| awk '/ SYN-SENT/&& $ NF!〜/^10./';睡眠2;できた
SYN-SENT 0 1 10.137.6.62:46088 74.125.203.94:32654
SYN-SENT 0 1 10.137.6.62:46088 74.125.203.94:32654
SYN-SENT 0 1 10.137.6.62:46088 74.125.203.94:32654

現在、私は企業ネットワークの内部にいます。ほぼ確実に、通常のポート80/443でgoogleへのアクセスがプロキシされ、他のポートはファイアウォールで保護されているため、RSTパケットが表示されることはありません。これが、質問で、REJECTとDROPの間のIPTablesルールの違いについて質問する理由です。 DROPは単にIPTablesのパケットを破棄しますが、REJECTはRSTを送信します。

次に、リスニングしていないポートへの接続をtcpdumpして、適切に更新します。

$ tcpdump -nn -t -i eth0 dst 8.8.8.8
tcpdump:警告:eth0:IPv4アドレスが割り当てられていません
tcpdump:詳細な出力が抑制されました。完全なプロトコルデコードには-vまたは-vvを使用してください
eth0、リンクタイプEN10MB(イーサネット)をリッスン、
キャプチャサイズ65535バイト
IP 10.137.6.62.40822> 8.8.8.8.12345:フラグ[S]、シーケンス505811469、勝利14600、オプション[mss 1460、sackOK、TS val 1513647100 ecr 0、nop、wscale 9]、長さ0
IP 10.137.6.62.40822 8.8.8.8.12345:フラグ[S]、シーケンス505811469、勝利14600、オプション[mss 1460、sackOK、TS val 1513648100 ecr 0、nop、wscale 9]、長さ0
IP 10.137.6.62.40822> 8.8.8.8.12345:フラグ[S]、シーケンス505811469、勝利14600、オプション[mss 1460、sackOK、TS val 1513650100 ecr 0、nop、wscale 9]、長さ0
IP 10.137.6.62.40822> 8.8.8.8.12345:フラグ[S]、seq 505811469、win 14600、オプション[mss 1460、sackOK、TS val 1513654100 ecr 0、nop、wscale 9]、長さ0
IP 10.137.6.62.40822> 8.8.8.8.12345:フラグ[S]、seq 505811469、win 14600、オプション[mss 1460、sackOK、TS val 1513662100 ecr 0、nop、wscale 9]、長さ0
IP 10.137.6.62.40822> 8.8.8.8.12345:フラグ[S]、seq 505811469、win 14600、オプション[mss 1460、sackOK、TS val 1513678100 ecr 0、nop、wscale 9]、長さ0

TODO:RSTパケットが表示されるように、ファイアウォールがない場合のtcpdumpを追加します。

警告Linuxに関する多くの有用な情報源がありますTCP接続デバッグ。RedHatはそのような情報源の1つです。それらのページの1つは、dropwatchツールを使用して、カーネルネットワーキングスタックのどこでパケットがドロップされるかを確立することを提案しています。 dropwatchツールは、終了したためにドロップされたパケットと、バッファオーバーフロー、または割り込みバジェットタイムアウトまたは...のためにドロップされたパケットを区別しません。

買い手責任負担。

0
Graham Nicholls