皆さん、こんにちは。私の名前は Sasha です。FunCorp でバックエンド テストを率いています。 他の多くの企業と同様に、当社もサービス指向アーキテクチャを実装しています。 一方で、これにより作業が簡素化されます。 各サービスを個別にテストする方が簡単ですが、その一方で、サービス間の相互作用をテストする必要があり、これはネットワーク上で頻繁に発生します。
この記事では、ネットワークに問題がある場合のアプリケーションの動作を説明する基本的なシナリオをチェックするために使用できる XNUMX つのユーティリティについて説明します。

ネットワーク問題のシミュレーション
通常、ソフトウェアはインターネット接続が良好なテスト サーバーでテストされます。 過酷な実稼働環境では、物事がそれほどスムーズに行われない可能性があるため、場合によっては、接続状態が悪い状態でプログラムをテストする必要があります。 Linux では、このユーティリティはそのような状況をシミュレートするタスクに役立ちます。 tc.
tc(略語。 交通管制から) を使用すると、システム内のネットワーク パケットの送信を設定できます。 このユーティリティには優れた機能があり、詳細についてはこちらをご覧ください。 。 ここでは、そのうちのいくつかだけを取り上げます。私たちは交通スケジュールに興味を持っており、これに使用します。 qディスク不安定なネットワークをエミュレートする必要があるため、クラスレス qdisc を使用します。 .
サーバー上でエコーサーバーを起動しましょう(私は使用しました) ):
ncat -l 127.0.0.1 12345 -k -c 'xargs -n1 -i echo "Response: {}"'
クライアントとサーバー間の対話の各ステップですべてのタイムスタンプを詳細に表示するために、リクエストを送信する単純な Python スクリプトを作成しました。 ホイール試乗 エコーサーバーに送信します。
クライアントのソースコード
#!/bin/python
import socket
import time
HOST = '127.0.0.1'
PORT = 12345
BUFFER_SIZE = 1024
MESSAGE = "Testn"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
t1 = time.time()
print "[time before connection: %.5f]" % t1
s.connect((HOST, PORT))
print "[time after connection, before sending: %.5f]" % time.time()
s.send(MESSAGE)
print "[time after sending, before receiving: %.5f]" % time.time()
data = s.recv(BUFFER_SIZE)
print "[time after receiving, before closing: %.5f]" % time.time()
s.close()
t2 = time.time()
print "[time after closing: %.5f]" % t2
print "[total duration: %.5f]" % (t2 - t1)
print data
起動してインターフェース上のトラフィックを見てみましょう lo およびポート 12345:
[user@host ~]# python client.py
[time before connection: 1578652979.44837]
[time after connection, before sending: 1578652979.44889]
[time after sending, before receiving: 1578652979.44894]
[time after receiving, before closing: 1578652979.45922]
[time after closing: 1578652979.45928]
[total duration: 0.01091]
Response: Test
トラフィックダンプ
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:42:59.448601 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [S], seq 3383332866, win 43690, options [mss 65495,sackOK,TS val 606325685 ecr 0,nop,wscale 7], length 0
10:42:59.448612 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [S.], seq 2584700178, ack 3383332867, win 43690, options [mss 65495,sackOK,TS val 606325685 ecr 606325685,nop,wscale 7], length 0
10:42:59.448622 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 0
10:42:59.448923 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 5
10:42:59.448930 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [.], ack 6, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 0
10:42:59.459118 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 606325696 ecr 606325685], length 14
10:42:59.459213 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 606325696 ecr 606325696], length 0
10:42:59.459268 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 606325696 ecr 606325696], length 0
10:42:59.460184 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 606325697 ecr 606325696], length 0
10:42:59.460196 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 606325697 ecr 606325697], length 0
すべてが標準です。XNUMX ウェイ ハンドシェイク、PSH/ACK と ACK の XNUMX 回の応答 (これはクライアントとサーバー間のリクエストと応答の交換です)、FIN/ACK と ACK の XNUMX 回で接続が完了します。
パケット遅延
次に、遅延を 500 ミリ秒に設定しましょう。
tc qdisc add dev lo root netem delay 500ms
クライアントを起動すると、スクリプトが 2 秒間実行されることがわかります。
[user@host ~]# ./client.py
[time before connection: 1578662612.71044]
[time after connection, before sending: 1578662613.71059]
[time after sending, before receiving: 1578662613.71065]
[time after receiving, before closing: 1578662614.72011]
[time after closing: 1578662614.72019]
[total duration: 2.00974]
Response: Test
渋滞には何があるの? 見てみよう:
トラフィックダンプ
13:23:33.210520 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [S], seq 1720950927, win 43690, options [mss 65495,sackOK,TS val 615958947 ecr 0,nop,wscale 7], length 0
13:23:33.710554 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [S.], seq 1801168125, ack 1720950928, win 43690, options [mss 65495,sackOK,TS val 615959447 ecr 615958947,nop,wscale 7], length 0
13:23:34.210590 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 615959947 ecr 615959447], length 0
13:23:34.210657 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 615959947 ecr 615959447], length 5
13:23:34.710680 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [.], ack 6, win 342, options [nop,nop,TS val 615960447 ecr 615959947], length 0
13:23:34.719371 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 615960456 ecr 615959947], length 14
13:23:35.220106 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 615960957 ecr 615960456], length 0
13:23:35.220188 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 615960957 ecr 615960456], length 0
13:23:35.720994 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 615961457 ecr 615960957], length 0
13:23:36.221025 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 615961957 ecr 615961457], length 0
クライアントとサーバー間の対話で、予想される 1 秒の遅延が発生していることがわかります。 遅延が大きい場合、システムはさらに興味深い動作をします。カーネルはいくつかの TCP パケットの再送信を開始します。 遅延を 4 秒に変更してトラフィックを見てみましょう (クライアントの出力は表示しません。合計所要時間は XNUMX 秒と予想されます)。
tc qdisc change dev lo root netem delay 1s
トラフィックダンプ
13:29:07.709981 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [S], seq 283338334, win 43690, options [mss 65495,sackOK,TS val 616292946 ecr 0,nop,wscale 7], length 0
13:29:08.710018 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [S.], seq 3514208179, ack 283338335, win 43690, options [mss 65495,sackOK,TS val 616293946 ecr 616292946,nop,wscale 7], length 0
13:29:08.711094 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [S], seq 283338334, win 43690, options [mss 65495,sackOK,TS val 616293948 ecr 0,nop,wscale 7], length 0
13:29:09.710048 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 616294946 ecr 616293946], length 0
13:29:09.710152 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 616294947 ecr 616293946], length 5
13:29:09.711120 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [S.], seq 3514208179, ack 283338335, win 43690, options [mss 65495,sackOK,TS val 616294948 ecr 616292946,nop,wscale 7], length 0
13:29:10.710173 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [.], ack 6, win 342, options [nop,nop,TS val 616295947 ecr 616294947], length 0
13:29:10.711140 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 616295948 ecr 616293946], length 0
13:29:10.714782 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 616295951 ecr 616294947], length 14
13:29:11.714819 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 616296951 ecr 616295951], length 0
13:29:11.714893 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 616296951 ecr 616295951], length 0
13:29:12.715562 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 616297952 ecr 616296951], length 0
13:29:13.715596 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 616298952 ecr 616297952], length 0
クライアントが SYN パケットを XNUMX 回送信し、サーバーが SYN/ACK を XNUMX 回送信したことがわかります。
遅延は、定数値に加えて、偏差、分布関数、および相関 (前のパケットの値との) に設定できます。 これは次のように行われます。
tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal
ここでは遅延を 100 ~ 900 ミリ秒に設定しています。値は正規分布に従って選択され、前のパケットの遅延値と 50% の相関関係があります。
お気づきかもしれませんが、最初に使用したコマンドでは 加えますそして 変化する。 これらのコマンドの意味は明らかなので、さらに多くのコマンドがあることを付け加えておきます。 インクルード、これを使用して構成を削除できます。
パケットロス
では、パケットロスを試してみましょう。 ドキュメントからわかるように、これは 2 つの方法で実行できます。3 つはある程度の確率でランダムにパケットを損失する方法、4、XNUMX、または XNUMX つの状態のマルコフ連鎖を使用してパケット損失を計算する方法、またはエリオット-ギルバート モデルを使用する方法です。 この記事では、最初の (最も単純で明白な) 方法を検討します。他の方法については読むことができます。 .
相関性 50% でパケットの 25% が損失するとします。
tc qdisc add dev lo root netem loss 50% 25%
残念なことに、 tcpdump パケットの損失を明確に示すことはできないため、実際に機能しているとのみ想定します。 また、スクリプトの実行時間が増加し、不安定になったことは、これを検証するのに役立ちます。 client.py (即座に完了するか、おそらく 20 秒以内に完了する可能性があります)、また再送信されるパケットの数が増加します。
[user@host ~]# netstat -s | grep retransmited; sleep 10; netstat -s | grep retransmited
17147 segments retransmited
17185 segments retransmited
パケットにノイズを加える
パケット損失に加えて、パケットの損傷もシミュレートできます。ランダムなパケット位置にノイズが発生します。 相関関係なしで 50% の確率でパケットにダメージを与えてみましょう。
tc qdisc change dev lo root netem corrupt 50%
クライアント スクリプトを実行し (何も興味深いものはありませんが、完了までに 2 秒かかりました)、トラフィックを確認します。
トラフィックダンプ
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:20:54.812434 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [S], seq 2023663770, win 43690, options [mss 65495,sackOK,TS val 1037001049 ecr 0,nop,wscale 7], length 0
10:20:54.812449 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [S.], seq 2104268044, ack 2023663771, win 43690, options [mss 65495,sackOK,TS val 1037001049 ecr 1037001049,nop,wscale 7], length 0
10:20:54.812458 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1037001049 ecr 1037001049], length 0
10:20:54.812509 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1037001049 ecr 1037001049], length 5
10:20:55.013093 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1037001250 ecr 1037001049], length 5
10:20:55.013122 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [.], ack 6, win 342, options [nop,nop,TS val 1037001250 ecr 1037001250], length 0
10:20:55.014681 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 1037001251 ecr 1037001250], length 14
10:20:55.014745 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 15, win 340, options [nop,nop,TS val 1037001251 ecr 1037001251], length 0
10:20:55.014823 IP 127.0.0.1.43666 > 127.0.0.5.12345: Flags [F.], seq 2023663776, ack 2104268059, win 342, options [nop,nop,TS val 1037001251 ecr 1037001251], length 0
10:20:55.214088 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [P.], seq 1:15, ack 6, win 342, options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>
10:20:55.416087 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 1037001653 ecr 1037001251], length 0
10:20:55.416804 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 1037001653 ecr 1037001653], length 0
10:20:55.416818 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 16, win 343, options [nop,nop,TS val 1037001653 ecr 1037001653], length 0
10:20:56.147086 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 1037002384 ecr 1037001653], length 0
10:20:56.147101 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 1037002384 ecr 1037001653], length 0
いくつかのパケットが繰り返し送信され、メタデータが壊れたパケットが XNUMX つあることがわかります。 オプション [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>。 しかし重要なことは、最終的にはすべてが正しく機能したということです。TCP はそのタスクに対処しました。
パケットの重複
他に何ができるでしょうか ネテム? たとえば、パケット損失の逆の状況、つまりパケットの重複をシミュレートします。 このコマンドは、確率と相関という 2 つの引数も受け取ります。
tc qdisc change dev lo root netem duplicate 50% 25%
パッケージの順序を変更する
バッグはXNUMX通りの方法で混ぜることができます。
最初の方法では、一部のパケットはすぐに送信され、残りのパケットは指定された遅延を持って送信されます。 ドキュメントの例:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50%
25% の確率 (相関関係は 50%) で、パケットはすぐに送信され、残りは 10 ミリ秒の遅延で送信されます。
XNUMX 番目の方法は、N 番目ごとのパケットが所定の確率 (および相関) で即座に送信され、残りのパケットが所定の遅延で送信される場合です。 ドキュメントからの例:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5
25 つごとの荷物が遅延なく送信される確率は XNUMX% です。
帯域幅の変更
通常、彼らが言及する場所はどこでも、 、しかし助けがあれば ネテム インターフェイスの帯域幅を変更することもできます。
tc qdisc change dev lo root netem rate 56kbit
このチームは各地をトレッキングします ローカルホスト ダイヤルアップ モデムを介してインターネットをサーフィンするのと同じくらい苦痛です。 ビットレートの設定に加えて、リンク層プロトコル モデルをエミュレートすることもできます。パケットのオーバーヘッド、セル サイズ、セルのオーバーヘッドを設定します。 たとえば、これをシミュレートできます ビットレート 56 kbit/秒:
tc qdisc change dev lo root netem rate 56kbit 0 48 5
接続タイムアウトのシミュレーション
ソフトウェアを受け入れるときのテスト計画におけるもう XNUMX つの重要な点は、タイムアウトです。 これは重要です。分散システムでは、サービスの XNUMX つが無効になっている場合、他のサービスは時間内に他のサービスにフォールバックするか、クライアントにエラーを返す必要があり、決して応答や接続を待って単にハングしてはなりません。確立されること。
これを行うにはいくつかの方法があります。たとえば、応答しないモックを使用するか、デバッガーを使用してプロセスに接続し、適切な場所にブレークポイントを設定してプロセスを停止します (これはおそらく最も邪悪な方法です)。 しかし、最も明らかなのは、ファイアウォールのポートまたはホストに対するものです。 これで私たちを助けてくれるでしょう .
デモンストレーションのために、ファイアウォール ポート 12345 を使用してクライアント スクリプトを実行します。 このポートへの送信パケットを送信側でファイアウォールし、受信パケットを受信側でファイアウォールできます。 この例では、受信パケットはファイアウォールで保護されます (チェーン INPUT とオプションを使用します) --dポート)。 このようなパケットは、DROP、REJECT、または TCP フラグ RST を伴う REJECT、または ICMP ホストが到達不能である場合の REJECT になる可能性があります (実際、デフォルトの動作は次のとおりです)。 icmp ポートに到達できません、返信を送信する機会もあります icmp-net-到達不能, icmp-proto-到達不能, icmp-net-禁止 и icmp-ホスト-禁止).
DROP
DROP を伴うルールがある場合、パケットは単純に「消滅」します。
iptables -A INPUT -p tcp --dport 12345 -j DROP
クライアントを起動すると、サーバーに接続する段階でフリーズすることがわかります。 トラフィックを見てみましょう。
トラフィックダンプ
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
08:28:20.213506 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203046450 ecr 0,nop,wscale 7], length 0
08:28:21.215086 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203047452 ecr 0,nop,wscale 7], length 0
08:28:23.219092 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203049456 ecr 0,nop,wscale 7], length 0
08:28:27.227087 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203053464 ecr 0,nop,wscale 7], length 0
08:28:35.235102 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203061472 ecr 0,nop,wscale 7], length 0
クライアントが指数関数的に増加するタイムアウトで SYN パケットを送信していることがわかります。 そこで、クライアントに小さなバグが見つかりました。メソッドを使用する必要があります。 セットタイムアウト()クライアントがサーバーへの接続を試行する時間を制限します。
ルールをすぐに削除します。
iptables -D INPUT -p tcp --dport 12345 -j DROPすべてのルールを一度に削除できます。
iptables -F
Docker を使用していて、コンテナーに送信されるすべてのトラフィックをファイアウォールする必要がある場合は、次のように実行できます。
iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP
拒否
次に、同様のルールを追加しましょう。ただし、REJECT が含まれています。
iptables -A INPUT -p tcp --dport 12345 -j REJECT
クライアントは XNUMX 秒後にエラーで終了します [エラー番号 111] 接続が拒否されました。 ICMP トラフィックを見てみましょう。
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
08:45:32.871414 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, length 68
08:45:33.873097 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, length 68
クライアントが XNUMX 回受信したことがわかります ポートに到達できません そしてエラーで終了しました。
tcp-reset による拒否
オプションを追加してみます --reject-with tcp-reset:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
この場合、最初のリクエストが RST パケットを受信したため、クライアントはエラーですぐに終了します。
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
09:02:52.766175 IP 127.0.0.1.60658 > 127.0.0.1.12345: Flags [S], seq 1889460883, win 43690, options [mss 65495,sackOK,TS val 1205119003 ecr 0,nop,wscale 7], length 0
09:02:52.766184 IP 127.0.0.1.12345 > 127.0.0.1.60658: Flags [R.], seq 0, ack 1889460884, win 0, length 0
icmp-host-unreachable で REJECT
REJECT を使用する別のオプションを試してみましょう。
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-host-unreachable
クライアントは XNUMX 秒後にエラーで終了します [エラー番号 113] ホストへのルートがありません、ICMP トラフィックで確認できます。 ICMP ホスト 127.0.0.1 に到達できません.
他の REJECT パラメーターを試すこともできます。ここではこれらに焦点を当てます :)
リクエストタイムアウトのシミュレーション
もう XNUMX つの状況は、クライアントがサーバーに接続できたものの、サーバーにリクエストを送信できない場合です。 フィルタリングがすぐに開始されないようにパケットをフィルタリングするにはどうすればよいですか? クライアントとサーバー間の通信トラフィックを見ると、接続の確立時には SYN フラグと ACK フラグのみが使用されますが、データ交換時には最後の要求パケットに PSH フラグが含まれることがわかります。 バッファリングを避けるために自動的にインストールされます。 この情報を使用してフィルタを作成できます。これにより、PSH フラグを含むパケットを除くすべてのパケットが許可されます。 したがって、接続は確立されますが、クライアントはサーバーにデータを送信できません。
DROP
DROP の場合、コマンドは次のようになります。
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP
クライアントを起動してトラフィックを監視します。
トラフィックダンプ
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:02:47.549498 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [S], seq 2166014137, win 43690, options [mss 65495,sackOK,TS val 1208713786 ecr 0,nop,wscale 7], length 0
10:02:47.549510 IP 127.0.0.1.12345 > 127.0.0.1.49594: Flags [S.], seq 2341799088, ack 2166014138, win 43690, options [mss 65495,sackOK,TS val 1208713786 ecr 1208713786,nop,wscale 7], length 0
10:02:47.549520 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1208713786 ecr 1208713786], length 0
10:02:47.549568 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208713786 ecr 1208713786], length 5
10:02:47.750084 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208713987 ecr 1208713786], length 5
10:02:47.951088 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208714188 ecr 1208713786], length 5
10:02:48.354089 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208714591 ecr 1208713786], length 5
接続は確立されていますが、クライアントがサーバーにデータを送信できないことがわかります。
拒否
この場合、動作は同じになります。クライアントはリクエストを送信できませんが、リクエストを受信します。 ICMP 127.0.0.1 tcp ポート 12345 に到達できません そして、リクエストの再送信までの時間が指数関数的に増加します。 コマンドは次のようになります。
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT
tcp-reset による拒否
コマンドは次のようになります。
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset
使用時にはすでにそれがわかっています --reject-with tcp-reset クライアントは応答として RST パケットを受信するため、動作は予測できます。接続が確立されている間に RST パケットを受信するということは、ソケットが反対側で予期せず閉じられていることを意味します。つまり、クライアントは受信する必要があります。 ピアによって接続がリセットされました。 スクリプトを実行してこれを確認してみましょう。 トラフィックは次のようになります。
トラフィックダンプ
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:22:14.186269 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [S], seq 2615137531, win 43690, options [mss 65495,sackOK,TS val 1209880423 ecr 0,nop,wscale 7], length 0
10:22:14.186284 IP 127.0.0.1.12345 > 127.0.0.1.52536: Flags [S.], seq 3999904809, ack 2615137532, win 43690, options [mss 65495,sackOK,TS val 1209880423 ecr 1209880423,nop,wscale 7], length 0
10:22:14.186293 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1209880423 ecr 1209880423], length 0
10:22:14.186338 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1209880423 ecr 1209880423], length 5
10:22:14.186344 IP 127.0.0.1.12345 > 127.0.0.1.52536: Flags [R], seq 3999904810, win 0, length 0
icmp-host-unreachable で REJECT
コマンドがどのようなものであるかは、すでに誰にとっても明らかだと思います :) この場合のクライアントの動作は、単純な REJECT の場合とは少し異なります。クライアントは、パケットの再送信を試行するまでのタイムアウトを増やしません。
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:29:56.149202 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.349107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.549117 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.750125 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.951130 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:57.152107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:57.353115 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
出力
ハングしたクライアントまたはサーバーとのサービスの対話をテストするためにモックを作成する必要はありません。場合によっては、Linux にある標準ユーティリティを使用するだけで十分です。
この記事で説明されているユーティリティには、説明されている機能よりもさらに多くの機能があるため、それらを使用するための独自のオプションをいくつか考え出すことができます。 個人的には、自分が書いた内容は常に十分にあります (実際には、さらに少なくなります)。 社内のテストでこれらのユーティリティまたは同様のユーティリティを使用する場合は、その方法を正確に書いてください。 そうでない場合は、提案された方法を使用して、ネットワークに問題がある状況でソフトウェアをテストすることに決めれば、ソフトウェアが改善されることを願っています。
出所: habr.com
