ネットワーク接続作業を行うと毎回のように何らかの問題が発生します。
pingは通るのに対向先のネットワーク機器にTCPコネクションが張れない、通信が突然切断された、そんな経験をしたことはありませんか?そういった事態に遭遇したとき、本記事がトラブルの元を突き止める手段のひとつとして参考になれば幸いです。
パケットキャプチャで原因を探る
問題発生の状況として、サーバーへpingは通るけれどssh接続ができない状態を想定します。
このような場合、次のような原因が考えられます。
- サーバーのポート22番が閉じている
- サーバーのFW機能で弾いている
- 経路上のFWで弾いている
原因を探るためパケットキャプチャしたところ、サーバーのIPアドレスからリセットパケットが送信されている事がわかりました。pingは問題なく通ります。
そこで問題です。
リセットパケットを送ったのは誰でしょうか?次のパケットキャプチャの結果から考えてみてください。
※192.168.31.128から192.168.40.129に対してping/sshを実行しています。サーバ(192.168.40.129)からの応答パケットに注目してみてください。
①IP (tos 0x0, ttl 128, id 2356, offset 0, flags [DF], proto: TCP (6), length: 52, bad cksum 0 (->283e)!) 192.168.31.128.49169 > 192.168.40.129.22: S, cksum 0xc978 (incorrect (-> 0x6b25), 2098519388:2098519388(0) win 8192②IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 192.168.40.129.22 > 192.168.31.128.49169: R, cksum 0xcbe4 (correct), 0:0(0) ack 2098519389 win 0 ③IP (tos 0x0, ttl 128, id 2357, offset 0, flags [DF], proto: TCP (6), length: 52, bad cksum 0 (->283d)!) 192.168.31.128.49169 > 192.168.40.129.22: S, cksum 0xc978 (incorrect (-> 0x6b25), 2098519388:2098519388(0) win 8192 ④IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 192.168.40.129.22 > 192.168.31.128.49169: R, cksum 0xcbe4 (correct), 0:0(0) ack 1 win 0 ⑤IP (tos 0x0, ttl 128, id 2358, offset 0, flags [DF], proto: TCP (6), length: 48, bad cksum 0 (->2840)!) 192.168.31.128.49169 > 192.168.40.129.22: S, cksum 0xc974 (incorrect (-> 0x7f34), 2098519388:2098519388(0) win 8192 ⑥IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 192.168.40.129.22 > 192.168.31.128.49169: R, cksum 0xcbe4 (correct), 0:0(0) ack 1 win 0 ⑦IP (tos 0x0, ttl 128, id 2359, offset 0, flags [none], proto: ICMP (1), length: 60, bad cksum 0 (->6838)!) 192.168.31.128 > 192.168.40.129: ICMP echo request, id 1, seq 1238, length 40 ⑧IP (tos 0x0, ttl 61, id 48987, offset 0, flags [none], proto: ICMP (1), length: 60) 192.168.40.129 > 192.168.31.128: ICMP echo reply, id 1, seq 1238, length 40 ⑨IP (tos 0x0, ttl 128, id 2360, offset 0, flags [none], proto: ICMP (1), length: 60, bad cksum 0 (->6837)!) 192.168.31.128 > 192.168.40.129: ICMP echo request, id 1, seq 1239, length 40 ⑩IP (tos 0x0, ttl 61, id 48988, offset 0, flags [none], proto: ICMP (1), length: 60) 192.168.40.129 > 192.168.31.128: ICMP echo reply, id 1, seq 1239, length 40 ⑪IP (tos 0x0, ttl 128, id 2361, offset 0, flags [none], proto: ICMP (1), length: 60, bad cksum 0 (->6836)!) 192.168.31.128 > 192.168.40.129: ICMP echo request, id 1, seq 1240, length 40 ⑫IP (tos 0x0, ttl 61, id 48989, offset 0, flags [none], proto: ICMP (1), length: 60) 192.168.40.129 > 192.168.31.128: ICMP echo reply, id 1, seq 1240, length 40 ⑬IP (tos 0x0, ttl 128, id 2362, offset 0, flags [none], proto: ICMP (1), length: 60, bad cksum 0 (->6835)!) 192.168.31.128 > 192.168.40.129: ICMP echo request, id 1, seq 1241, length 40 ⑭IP (tos 0x0, ttl 61, id 48990, offset 0, flags [none], proto: ICMP (1), length: 60) 192.168.40.129 > 192.168.31.128: ICMP echo reply, id 1, seq 1241, length 40
答えは次のどちらでしょう??
- サーバーがリセットパケットを送信した
- 経路上にあるネットワーク機器がリセットパケットを送信した
答えは次の章で。IPヘッダーの値に注目してください。
IPヘッダーはウソをつかない
だれがリセットパケットを送信したのかすぐにわかりましたか?確信を持って即答できなければ、このまま読み進めてください。
正解は2番。「経路上にあるネットワーク機器がリセットパケットを送信した」です。
このような状況で注目するべきは、IPヘッダーの「TTL」値です。
TTLはIPヘッダーに含まれる8ビットの値で、ネットワーク機器を経由するごとに、ひとつずつTTL値が減ります。Tracerouteはこの仕組みを利用して通信経路を調べています。
では実際にTTL値に注目してパケットキャプチャの結果を追いかけてみましょう。
まずキャプチャ結果の②のTTL値に注目してください。TTL値は63です。このパケットはssh接続が切断されるとき、サーバーからリセットパケットが送信されてきたときのものです。
②IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto: TCP (6), length: 40) 192.168.40.129.22 > 192.168.31.128.49169: R, cksum 0xcbe4 (correct), 0:0(0) ack 2098519389 win 0
次に⑧に注目してください。このときのTTL値は61です。これはサーバーからICMP応答を受信したときのものです。
⑧IP (tos 0x0, ttl 61, id 48987, offset 0, flags [none], proto: ICMP (1), length: 60) 192.168.40.129 > 192.168.31.128: ICMP echo reply, id 1, seq 1238, length 40
おかしくありませんか?送信元IPアドレスは同じなのにどうしてTTL値が違うのでしょう?
その答えをつぎのフロー図で説明します。
このフロー図は、pingを実行したときとssh接続がリセットパケットで切断されたときの通信の流れを示しています。
pingを実行したとき、パケットはFWを通過してサーバーがping応答を送信しました。このとき、サーバーが設定した初期TTL値は64です。その後、ルーターとFWを経由してping応答が到着するとTTL値は61まで減算されました。パケットキャプチャの結果と一致しています。
これに対してsshが切断されたときはどうでしょうか?まずFWのポリシーに引っかかってFWで止められます。そしてFWはリセットパケットを送信します。偶然にもサーバーと同じくFWの初期TTL値も64でしたので、ルーターを経由してリセットパケットが送信元へ到達したときTTL値は63に減算されました。
興味深いことに、TTLの初期値はOSのTCP/IP実装に依存します。そして、カーネルパラメータをいじらない限りTTLの初期値は「64」「128」「255」のどれかである事が多いです。そのため、返って来たTTL値をみれば送信元の初期TTL値は簡単に推測できます。初期TTL値はわかっているので、逆算すればホップ数もおのずと推測できます。今回の例でいえばリセットパケットを投げたネットワーク機器(FW)の間にひとつネットワーク機器がある事がわかるはずです。
何もしていないのに切断されるとき
今回はキャプチャ結果を掲載していないのですが、アプリテストをしていると不意に通信切断が発生する事があります。このときの原因で多いのはFWやLB(ロードバランサー)がタイムアウトしてリセットパケットを飛ばした場合です。
リセットパケットで通信が切断された場合はパケットキャプチャをしていれば一発で送信元を特定できる可能性が極めて高いです。経路上でリセットパケットを飛ばしそうなネットワーク機器のパラメータ再確認をするという地道な方法も良いのですが(昔やらされました)、迅速に解決したいならばパケットキャプチャをした方が良いでしょう。
FWやLBの設定が甘いと必ず発生するので試してみてください。
最後に
TTLに注目すると、ホップ数の変化によって隠れたネットワーク構成や通信の流れの変化を知る手がかりになります。トラブルシューティングの際は重要な手がかりになることがあるので、頭の片隅に置いておくと役に立つ日がくるかも知れません。
この記事は役に立ちましたか?
もし参考になりましたら、下記のボタンで教えてください。
コメント