TCPが再送しているケースだけではない?WiresharkでBad TCPが発生する原因

自宅でリモートワーク中に自分の通信をWiresharkでキャプチャしていると、実に多くの黒いパケットが発生していたりします。この黒いパケットの正体は、Wiresharkのデフォルトカラーリング設定の"Bad TCP"に分類されたパケットです。
自宅までは光通信となっていて、その先にはWifiルータを設置していて、PCとは無線で接続していますが、とても早くて快適です。遅いとか繋がらないとかいうことは一切感じません。

Wireshark Bad TCPパケットフィルタ|自宅での通信状況

Wiresharkでキャプチャした自宅の通信パケット(Bad TCPのみフィルタ)

今回は、Wiresharkで検出されるいくつかの"Bad TCP"について、そのアラートの種類となぜそのアラートが表示されるのかを解説します。

WiresharkでBad TCPパケットをフィルタする方法

WiresharkでBad TCPパケットをフィルタする場合はパラメータを指定します。

tcp.analysis.flags && !tcp.analysis.window_update && !tcp.analysis.keep_alive && !tcp.analysis.keep_alive_ack
Bad TCPフィルタ。TCPのシーケンス番号の異常等を検出する場合に使用します。

以前紹介したWiresharkの表示フィルタ ~基本操作編~では、パケットに含まれる情報についての操作方法を解説しました。
今回のBad TCPは、パケットに含まれる情報ではありません。Wiresharkは、パケットに含まれる情報をもとに前後のパケットとの関連性からパケットを解析する機能を持っています。Wiresharkが独自で解析した結果は、以下のように[]で表示され、一部をのぞき[]で表示された情報はパケットに含まれていません。

Wiresharkの詳細/Hex表示 |TCP解析に基づいた表示

Bad TCP以外にもTCP関連でパケットに含まれない情報でのフィルタパラメータを一部ご紹介します。

tcp.completeness == <value>
TCPセッションのメッセージのやりとりがどの段階まで行われたかを指定するフィルタ。段階はTCPフラグのビットを積算した数で設定します。
TCPフラグの各ビットの値
たとえば3ウェイハンドシェークのみの通信のフィルタは、1(SYN)+2(SYN/ACK)+4(ACK)から、'tcp.completeness==7'となります。
tcp.stream == <value>
TCPストリーム単位でのフィルタ。Wiresharkは自動的にストリーム番号を生成しているので、同じストリームのパケットをフィルタする場合に使用します。

実は、Wiresharkはこれ以外にもTCP関連フィルタは充実しています。他のプロトコルに比べデコード画面を見た際に[]の表示が多いことからもそのことが言えるかと思います。

TCPの再送が発生する仕組み

「TCPは信頼性があるプロトコル」という言葉をよく聞きますが、この理由は、TCPは受信者がデータをどこまで受け取ったかを確認し、受信していないデータがあった場合には再送する仕組みが備わっているからです。
具体的には、TCPは互いにシーケンス番号(以下Seq#)と確認応答番号(以下Ack#)を自分自身のパケットに設定して相手に送ることにより、どのデータを送信したか、どこまでデータを受信したかを通知することで、会話を成立させます。下図は、再送がどのような場合に再送が発生するかを示しました。(概念的につかんでいただくため、Seq#、Ack#、TCP lengthの表記はしていません。)

TCPの再送アルゴリズム

Aliceをデータ送信者、Bobをデータ受信者とした場合、相手にパケットが届かない、すなわち経路上でパケットが失われるケースは「AliceのパケットがBobに届かない場合」「BobのパケットがAliceに届かない場合」の2通りが想定されます。さらにキャプチャデータ上では、「通信上は問題ないにもかかわらずキャプチャ装置がロスしている場合」も考えられます。
したがって、Wiresharkのアラートの中にはトラブルシューティングしている問題には直接関係しないものも存在しますので、注意が必要です。

なお、図はわかりやすくするためにひとつひとつのデータに応答確認するような表現となっていますが、TCPは、「スライディングウィンドウ」「高速再送」「SACK」等を使ってさらに効率的な通信を行っています。実際に自分のPCのWiresharkでキャプチャを開始し、Webにアクセスしたパケットを確認してみてください。まとめてACKを返している状態が確認できると思います。

Bad TCPアラートが表示される原因

以下は、Bad TCPアラートの中でもよく見られるシーケンス上の異常について解説します。Wireshrakのアラートの判定については、Wireshark User's Guide - TCP Analysisに詳細が記載されていますので、あわせてご覧ください。

上の図と同様、Aliceをデータ送信者、Bobをデータ受信者として説明しています。ここではAlice側にマークされるアラートとBob側にマークされるアラートでわけて記載しています。

Alice(送信者)側にマークされるアラート

TCP Retransmission

Aliceからのデータ再送パケットにマークされるアラートです。Bobから次に期待されるSeq#がRTO(再送タイムアウト)までに返ってこない場合、Aliceはデータを再送信します。

次のすべてが当てはまる場合に設定されます。

  • キープアライブパケットではない
  • セグメント長がゼロより大きいか、SYNまたはFINフラグが設定されている
  • 次に期待されるSeq#は、現在のSeq#より大きい

TCP Out-Of-Order

Aliceからのパケットにマークされるアラートです。Seq#が進んでいない状態で、一番大きいSeq#のパケットからiRTTしきい値以内にそれよりも小さいSeq#のパケットが確認された際にマークされます。これは実際に順序が入れ替わって届いた場合や、iRTT以内に要求された再送パケットが確認された場合等が考えられます。

次のすべてが当てはまる場合に設定されます。

  • キープアライブパケットではない
  • Aliceのパケットで、セグメント長がゼロより大きいか、SYNまたはFINフラグが設定されている
  • 次に期待されるSeq#は、現在のSeq#より大きい
  • 次に期待されるSeq#と次のSeq#は異なる
  • 最後のAliceからのパケットが、Out-Of-Order RTTしきい値以内に確認された
    しきい値は、「SEQ/ACK分析」の「iRTT」(tcp.analysis.initial_rtt) フィールドに表示される値か、または存在しない場合のデフォルト値の3msとなる

TCP Fast Retransmission

Aliceからのデータ再送パケットにマークされるアラートです。TCP Retransmissionとは異なり、通常のRTOからの再送ではなく、TCPの高速再送(重複Ackを3回以上受信するとRTOを待たずに再送)によるものになります。Wiresharkの仕様では、(Wiresharkでのパケットロスも考慮してか)重複Ackを2回以上でマークされる条件となっています。

次のすべてが当てはまる場合に設定されます。

  • キープアライブパケットではない
  • Aliceからのパケットが、セグメント長がゼロより大きい、もしくはSYNまたはFINフラグが設定されている
  • Bobからのパケットで次に期待されるSeq#は、現在のSeq#より大きい
  • Bobからのパケットで重複ACKが少なくとも2つ存在している
  • Aliceの現在のSeq#は、Bobからの次に期待されるAck#と同じ
  • Bobからの最後のAckは20ミリ秒以内に確認された

これらすべてが当てはまる場合、「Out-Of-Order」と「Retransmission」から置き換わります。

TCP Spurious Retransmission

Aliceからのパケットにマークされます。本来BobからのAckによりAliceは再送が必要ないはずなのにもかかわらず再送しています。もっとも可能性が高い要因は、BobのAckパケットがキャプチャされたあとにAliceに到達する間にパケットが失われた場合です。(つまりトラブル箇所はBobとキャプチャ装置の間ではなく、キャプチャ装置とAliceの間にあるということです。)

次のすべてが当てはまる場合に設定されます。

  • キープアライブパケットではない
  • セグメント長がゼロより大きい
  • すでにAliceからこのSeq#のデータが送信され、それに対するAck#がBobから送信されている
  • Bobからの次に期待されるSeq#は、最後に確認されたAck#以下

これらすべてが当てはまる場合、「TCP Fast Retransmission」、「Out-Of-Order」、および「Retransmission」から置き換わります。

なお、Wireshark User's GuideVersion 4.3.0では、TCP Spurious Retransmissionの条件のひとつに"The SYN or FIN flag is set."との表記がありますが、そもそもこのアラートはデータにマークされるパケットですので誤りではないでしょうか。自宅でキャプチャした際にも、TCP Spurious Retransmissionパケットには、SYN、FINフラグが設定されていないことを確認しました。(Wireshrakに詳細な仕様を問い合わせしています。)

Wireshark TCP Spurious Retransmission|自宅で検証したTCP Spurious Retransmissionのパケット

自宅で検証したTCP Spurious Retransmissionのパケット

TCP Previous segment not captured

Aliceからのパケットにマークされます。現在のSeq#が次に期待されるSeq#より大きい場合に設定されます。
これは本来見えているはずのAliceのパケットがキャプチャ装置もしくは実際のネットワーク上でパケットをロスをしています。またセッションの途中にキャプチャを開始した場合は、当然キャプチャ前のパケットは確認できませんので、このアラートがマークされます。

Bob(受信者)側にマークされるアラート

TCP Dup ACK <frame>#<acknowledgment number>

BobからのAckパケットにマークされます。Wireshark上で過去の通信と同じAck#が観測された際に表示されます。Bobが同じAck#でAliceに送信する理由は、Bobがデータを受信できなかったためです。ですので、経路上でAliceのパケットが失われている可能性が高いです。

次のすべてが当てはまる場合に設定されます。

  • セグメント長がゼロ
  • ウィンドウサイズはゼロではなく、変更されていない
  • 次に期待されるSeq#と最後に確認されたAck#は0でない (つまりコネクションが確立されている)
  • SYN、FIN、RSTフラグは設定されていない

TCP ACKed unseen segment

BobからのAckパケットにマークされます。Wireshark上でAliceのデータがないにもかかわらず、BobからはそのデータのAckが返されている状況です。「TCP Previous segment not captured」と同じようにキャプチャ装置がパケットロスをしている、もしくはAliceのデータはキャプチャ開始前に存在していた、ということが考えられます。
ただし、データに対するAckパケットが存在しているということは、「TCP Previous segment not captured」とは違い経路上でAliceのパケットが失われている、という可能性はありません。言い換えると、TCP上はまったく問題がなく通信ができているということです。

パケットキャプチャ装置でロスがないということ

当社で開発、販売しているパケットキャプチャ製品「SYNESIS」の一番の特長は、パケット長にかかわらず性能を担保し、キャプチャ中にパケットロスをさせない設計になっているということです。パケットキャプチャ装置に信頼性がないと、あるべきパケットが実際にネットワーク上に存在しなかったのか、パケットキャプチャ装置がロスしたのかの判断がつきません。トラブルシューティングにあたり、パケットキャプチャ装置自体でのパケットロスの可能性を排除することで、はじめてキャプチャされたパケットデータを信頼できるようになります。

パケットキャプチャ装置「SYNESIS(シネシス)」|100Gbpsでパケットロスなしの性能

1Gから100Gまでの各種回線のモデルをご用意しています。SYNESISにご興味がありましたら、以下よりお問い合わせください。

SYNESIS お問い合わせ

あとがき

通信は快適でもパケットを可視化した際にはいろいろとアラートが出ていることがよくあります。その中にはセッションの途中でキャプチャされているため、実際には正常な通信かもしれません。黒い表示がすべて異常ということではありません。Wiresharkは、あくまでパケットの中身とパケットが届いた順番で判断しているにすぎません。
パケットキャプチャを勉強しなきゃと思っている方は、身近なパケットをキャプチャすることからはじめてみてはいかがでしょうか。自分の想定とは違った意外なことが発見できるかもしれません。

今回の私の発見は、IPv6での通信の割合が想定より多いことでした。WiresharkのProtocol Hierarchy StatisticsでIPv6の割合は7.5%でした。(作業によると思いますが、私はもっと少ないかと思っていました。)Googleの統計でIPv6の採用状況のグラフがありましたので掲載します。

ここ10年弱くらいでやっとIPv6が普及しはじめた、というトレンドがグラフからは読み取れます。IPv6の仕様として最初に発行されたRFC1883は、1995年に発行されておりすでに30年近く経過します。現在のStandard TrackはRFC8200で、こちらは2017年発行となっています。TCPにはおよばないまでも、IPv6もRFC上は結構歴史があるプロトコルであることがいえます。

Englishi Contents of Engineer Notes