パケット解析は奥が深く書き出すと膨大な量になってしまうので、取っかかりの入門として解析ツールの使い方と簡単な解析事例をご紹介します。
タップできる目次
パケット解析するためのツール
*BSDやMacを使っているならば最初からtcpdumpがインストールされているはずです。ネットワーク機器ではBIG-IPやCheckPoint社のFWがLinuxベースなので、これもtcpdumpが使えます。WindowsはWindow7以降でパケットキャプチャが可能です(後述)。
RedHat Enterprise LinuxやCentOSはデフォルトではtcpdumpがインストールされていないので、別途インストールする必要があります。次のようにしてインストールします。
# yum -y install tcpdump
どうしてもGUIでなきゃ嫌だっていう人もいるかも知れません。まぁそれも良いでしょう。そういう人はWireSharkを使いましょう。WireSharkはWindowsでもLinuxでもMacでも使えます。WireSharkの良いところは統計やtcp flowを視覚化できるところです。WireSharkをインストールするとコマンドライン版のtsharkも一緒にインストールされます。
WireSharkを使うにしても、ネットワークに携わるならばtcpdumpを使えるようにしておく必要があります。
Windowsでパケットキャプチャする
WireSharkやWindumpなどサードパーティー製のソフトウェアがインストールされていない場合、netshコマンドでパケットキャプチャをおこなうことができます。
netshコマンドでキャプチャ
管理者権限でコマンドプロンプトを立ち上げてnetshコマンドを実行します。
以下は出力ファイルを「D:net.etl」、「D:net.etl」のサイズをデフォルトの250MBから1MBへ変更、IPアドレスが8.8.8.8のパケットをキャプチャする様子です。停止は「netsh trace stop」を実行します。
プロンプトが戻ってきたらパケットキャプチャができる事を確認するために、8.8.8.8へpingを打ってみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
C:WINDOWSsystem32>ping 8.8.8.8 8.8.8.8 に ping を送信しています 32 バイトのデータ: 8.8.8.8 からの応答: バイト数 =32 時間 =17ms TTL=57 8.8.8.8 からの応答: バイト数 =32 時間 =20ms TTL=57 8.8.8.8 からの応答: バイト数 =32 時間 =16ms TTL=57 8.8.8.8 からの応答: バイト数 =32 時間 =9ms TTL=57 8.8.8.8 の ping 統計: パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、 ラウンド トリップの概算時間 (ミリ秒): 最小 = 9ms、最大 = 20ms、平均 = 15ms C:WINDOWSsystem32> |
netsh trace stopコマンドでパケットキャプチャを止めます。
1 2 3 4 5 6 7 8 9 |
C:WINDOWSsystem32>netsh trace stop トレースを関連付けています... 完了 トレースの結合中... 完了 データ収集を生成しています ... 完了 トレース ファイルと追加のトラブルシューティング情報は、"D:net.cab" としてコンパイルされました。 ファイルの場所 = D:net.etl トレース セッションは正常に停止しました。 C:WINDOWSsystem32> |
パケットキャプチャに指定できるフィルターは「netsh trace show capturefilterhelp」で確認することができます。
キャプチャファイルを解析する
etlファイルはMicrosoft Message Analyzerで解析できます。以下のURLからダウンロードしてインストールします。
WireSharkやtcpdumpで解析するためにはpcap形式に変換する必要があります。pcap形式へ変換するためにはMicrosoft Message Analyzerでetlファイルを開いた後、[File]-[Save As]からStep 1でAll Messages、Step 2でExportをクリックしてpcap形式で書き出します。

tcpdumpパケットフィルターコマンドの使い方
ネットワークには膨大な量のパケットが流れているので、パケットフィルターコマンドを適切に使用する必要があります。パケットフィルターコマンドは、パケット受信時でも保存したキャプチャーファイルを読み込む時のどちらでも使用できます。
プロトコルを指定する
tcpやudp、icmpやarpなどを指定できます。複数のプロトコルを指定したい場合は「or」を使います。
- tcp or udp
- tcp
ホストを指定する
hostコマンドを使用すると、送信元や送信先のホストを指定できます。
- host 192.168.2.1
- host 192.168.2.1 or 192.168.2.100
ネットワークを指定する
netコマンドを使用すると、送信元や送信先のネットワークを指定できます。
- net 192.168.2.0/24
ポート番号を指定する
portコマンドを使用すると、送信元や送信先のポート番号を指定できます。
- port 80
方向を指定する
今まで列挙したコマンドは送信元や送信先に関わらずマッチします。src/dstコマンドを使用すると、方向を指定できます。andやorを組み合わせると、より詳細にマッチさせる事ができます。
- src host 192.168.2.1
- dst host 192.168.2.200 and port 80
- src net 192.168.2.0/24 and dst host 172.16.31.1 and “(port 80 or 8080)”
TCPセッションフラグを指定する
SYNやFIN、RSTなどTCPセッションフラグの値を指定できます。
ビット演算子の&(アンド)で特定のビットが立っているか調べます。次の例はRSTフラグが立っているパケットにマッチします。
- “tcp[tcpflags] & tcp-rst != 0”
次の例はRSTもしくはFINフラグが立っているパケットにマッチします。
- “tcp[tcpflags] & (tcp-rst|tcp-fin) != 0”
特定の範囲の値を指定する
IPヘッダーのnバイト目が○である、とかTCPヘッダーのnバイト目が○以上である、といった指定ができます。
次の例は、TCPヘッダーの先頭から14バイト目から2バイトの値(TCP WINDOW)が40(0x28)であるパケットにマッチします。
- “tcp[14:2] == 40”
- “tcp[14:2] == 0x28”
次の例はTCPヘッダーの先頭から14バイト目から2バイトの値が40未満のパケットにマッチします。
- “tcp[14:2] < 40”
tcpdumpコマンドオプション
よく使うオプションを紹介します。
-n ホスト名を解決させない
-nn ホスト名の解決に加えてプロトコル名やポート番号も解決させない
-i <インタフェース名> 受信するインタフェースを指定する
-w <ファイル名> 受信パケットをpcap形式で保存するファイル名を指定する
-s <受信サイズ> 受信サイズを指定する
-S シーケンス番号を絶対値で表示する
-t タイムスタンプを表示しない
-tt タイムスタンプを整形せずに表示する
-ttt 直前に受信した時刻からの経過時間を表示する
-tttt 現在の日付と時刻を整形して表示する
-ttttt パケット受信を開始した時刻からの経過時間を表示する
-x パケットを16進数でダンプする
-X パケットを16進数でダンプし、併せてパケットの内容をアスキー表示させる
-v 詳細表示モードにする
-vv 更に詳細な表示モードにする
-vvv 最も詳細な表示モードにする
-e イーサネットヘッダーも表示する
-r <ファイル名> pcap形式で保存したファイルを読み込む
-c <カウント数> カウント数のパケットを受信したらtcpdumpを終了する
-C <サイズ> MB単位でローテーションするサイズを指定する
-W <個数> ファイルをローテーションする個数を指定する
キャプチャファイルのローテーション
キャプチャファイルを保存する領域のサイズが限られている際、ローテーションするサイズと個数を指定する事によって解決できます。
たとえばキャプチャするファイルサイズの上限を100MBにしたければ次のようにします:
- tcpdump -W 1 -C 100
こうすると、キャプチャファイルが100MBに達すると新たにファイルが作られる事なく同一ファイル名でローテーションします。稀にしか再現しない障害などを調査する目的で延々とキャプチャを続けなければならない場面で役に立ちます。
TCPの解析例
パケット解析するためには、パケットの構造を熟知している必要があります。
TCP/IPヘッダ構造
3ステップハンドシェーク(3ウェイハンドシェーク)
TCPは次の手順で3ステップハンドシェークによる接続を確立させます。
- クライアントからサーバーへSYNを送信する
- サーバーがクライアントへSYN+ACKを送信する
- クライアントがサーバーへACKを送信する
次の例は、yahoo.co.jpへHTTP接続する様子をtcpdumpで受信した時の結果です。
123456789101112
IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [S], seq 3917004649, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1014815386 ecr 0,sackOK,eol], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [S.], seq 3111149831, ack 3917004650, win 14480, options [mss 1414,sackOK,TS val 2466821728 ecr 1014815386,nop,wscale 9], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111149832, win 4118, options [nop,nop,TS val 1014815574 ecr 2466821728], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [P.], seq 3917004650:3917005380, ack 3111149832, win 4118, options [nop,nop,TS val 1014815575 ecr 2466821728], length 730: HTTP: GET / HTTP/1.1IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005380, win 32, options [nop,nop,TS val 2466821906 ecr 1014815575], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], seq 3111149832:3111151234, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 1402: HTTP: HTTP/1.1 301 Moved PermanentlyIP 182.22.59.229.80 > 192.168.2.9.63382: Flags [P.], seq 3111151234:3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 642: HTTPIP 182.22.59.229.80 > 192.168.2.9.63382: Flags [F.], seq 3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821908 ecr 1014815575], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151876, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821907], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151877, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [F.], seq 3917005380, ack 3111151877, win 4096, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005381, win 32, options [nop,nop,TS val 2466821918 ecr 1014815585], length 0
マーキングしている1〜3行目が3ステップハンドシェークを行っている箇所です。
- クライアントからサーバーへSYNを送信(初期シーケンス番号 3917004649)
- サーバーがクライアントへSYN+ACKを送信(初期シーケンス番号 3111149831/確認応答番号 3917004650)
- クライアントがサーバーへACKを送信して接続完了(確認応答番号 3111149832)
コネクション切断
トラブルシューティングを行う場合は、TCPコネクションがどのように遷移するのか知っている必要があります。とても重要なことなので、rfc793から抜粋したTCPの遷移図を掲載します。
1234567891011121314151617181920212223242526272829303132333435363738394041424344
+---------+ --------- active OPEN | CLOSED | ----------- +---------+<--------- create TCB | ^ snd SYN passive OPEN | | CLOSE ------------ | | ---------- create TCB | | delete TCB V | +---------+ CLOSE | | LISTEN | ---------- | | +---------+ delete TCB | | rcv SYN | | SEND | | ----------- | | ------- | V +---------+ snd SYN,ACK / snd SYN +---------+ | |<----------------- ------------------>| | | SYN | rcv SYN | SYN | | RCVD |<-----------------------------------------------| SENT | | | snd ACK | | | |------------------ -------------------| | +---------+ rcv ACK of SYN / rcv SYN,ACK +---------+ | -------------- | | ----------- | x | | snd ACK | V V | CLOSE +---------+ | ------- | ESTAB | | snd FIN +---------+ | CLOSE | | rcv FIN V ------- | | ------- +---------+ snd FIN / snd ACK +---------+ | FIN |<----------------- ------------------>| CLOSE | | WAIT-1 |------------------ | WAIT | +---------+ rcv FIN +---------+ | rcv ACK of FIN ------- | CLOSE | | -------------- snd ACK | ------- | V x V snd FIN V +---------+ +---------+ +---------+ |FINWAIT-2| | CLOSING | | LAST-ACK| +---------+ +---------+ +---------+ | rcv ACK of FIN | rcv ACK of FIN | | rcv FIN -------------- | Timeout=2MSL -------------- | | ------- x V ------------ x V snd ACK +---------+delete TCB +---------+ ------------------------>|TIME WAIT|------------------>| CLOSED | +---------+ +---------+
それでは、先ほど掲載したtcpdumpの結果を再掲載します。マーキングした箇所がTCPコネクションの切断を行っている箇所です。
123456789101112
IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [S], seq 3917004649, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1014815386 ecr 0,sackOK,eol], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [S.], seq 3111149831, ack 3917004650, win 14480, options [mss 1414,sackOK,TS val 2466821728 ecr 1014815386,nop,wscale 9], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111149832, win 4118, options [nop,nop,TS val 1014815574 ecr 2466821728], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [P.], seq 3917004650:3917005380, ack 3111149832, win 4118, options [nop,nop,TS val 1014815575 ecr 2466821728], length 730: HTTP: GET / HTTP/1.1IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005380, win 32, options [nop,nop,TS val 2466821906 ecr 1014815575], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], seq 3111149832:3111151234, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 1402: HTTP: HTTP/1.1 301 Moved PermanentlyIP 182.22.59.229.80 > 192.168.2.9.63382: Flags [P.], seq 3111151234:3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 642: HTTPIP 182.22.59.229.80 > 192.168.2.9.63382: Flags [F.], seq 3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821908 ecr 1014815575], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151876, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821907], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151877, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [F.], seq 3917005380, ack 3111151877, win 4096, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005381, win 32, options [nop,nop,TS val 2466821918 ecr 1014815585], length 0
順に追ってみましょう。
- 8行目:クライアントがFINを送信して「FIN-WAIT-1」へ遷移する。
- 9行目:FINを受信したサーバーはACK送信して「CLOSE WAIT」へ遷移する。クライアントはサーバーからACKを受信して「FIN WAIT-2」へ遷移する。
- 10行目:サーバーがFINを送信して「LAST ACK」へ遷移する。
- 11行目:FINを受信したクライアントはFIN+ACKを送信して「TIME WAIT」へ遷移する。
- 12行目:サーバーはFIN+ACKを受信して「CLOSED」へ遷移する。クライアントはタイムアウトして「CLOSED」へ遷移する。
選択確認応答(sack)
従来の累積確認応答はパケットを受信するごとに確認応答を返す、というやり取りを行っていました。この方法は信頼性があるのですが、やり取りが多くなるため効率が悪くなってしまいます。そこで、スライディングウィンドウというものを利用することになりました。これは簡単にいうと受信バッファが空いている間は確認応答を待たなくても連続して送信して良い、というものです。ここでいう受信バッファというのはTCP Windowサイズのことです。スライディングウィンドウは高速通信環境ではスループットを高めてくれますが、途中でパケットを喪失すると最後に確認応答したところからやり直す必要があります。また、高遅延な通信環境ではスループットの低下が顕著になります。
そこで、喪失したパケットだけ再送信して効率化を高めましょう、という発想から生まれたのが選択確認応答(sack)です。
それでは実際に再送している様子をtcpdumpで観察してみましょう。ちょっと長いので、スマートフォンでは見づらいかも知れません。
12345678910111213141516171819202122232425262728293031323334353637383940
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3354, options [nop,nop,TS val 342395 ecr 4051066186], length 36IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3408, options [nop,nop,TS val 342447 ecr 4051066186], length 36IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3408, options [nop,nop,TS val 342499 ecr 4051066186], length 36IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717859270:3717860718, ack 1766368136, win 303, options [nop,nop,TS val 4051072656 ecr 342395], length 1448IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717860718:3717863614, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 2896IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717863614, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717863614:3717867958, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 4344IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717867958, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717867958:3717869406, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 1448IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717869406, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717869406:3717873750, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 4344IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717873750, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717873750:3717880990, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 7240IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717880990, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717880990:3717888230, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 7240IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717888230, win 3373, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717888230:3717896918, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 8688IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717896918, win 3316, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717896918:3717907054, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717907054, win 3250, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717907054:3717943254, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 36200IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717943254, win 3022, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717943254:3717950494, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 7240IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717950494, win 3127, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717950494:3717954838, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 4344IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717954838, win 3097, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717954838:3717966422, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 11584IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717966422, win 3394, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717966422:3717967870, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 1448IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717967870, win 3408, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717967870:3717979454, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 11584IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717979454, win 3394, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717979454:3717989590, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717992486, win 3403, options [nop,nop,TS val 344023 ecr 4051072696], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717992486:3718022894, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 30408IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3718022894, win 3298, options [nop,nop,TS val 344024 ecr 4051072696], length 0IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3718022894:3718031582, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 8688
順を追ってsackによる再送の様子を説明します。少し長くなりますがパケットキャプチャの結果と併せて見てください。
5行目でクライアントは確認応答番号として3717860718を送信しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656], length 0
そのため次にクライアントが受信するべきシーケンス番号は3717860718のはずですが、6行目で受信したシーケンス番号は3717989590です。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896
3717989590 – 3717860718は128,872ですから、128,872バイトを5行目と6行目の間に喪失した事になります。
クライアントはパケットの喪失をここで検知しました。
そして喪失した部分を埋めるために、クライアントは7行目でsackを送信します。シーケンス番号3717989590以前のパケットを喪失したため再送する必要がある事をsackで伝えています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656,nop,nop,sack 1 {3717989590:3717992486}], length 0
このsackにより、サーバーはクライアントから受信した確認応答番号3717860718からsackで通知された3717989590までの128,872バイトを再送する必要があるとわかります。
8行目からサーバーは最初に喪失したシーケンス番号3717860718のパケットを再送します。tcpdumpの出力では次のようにシーケンス番号が表示されています。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717860718:3717863614, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 2896
このとき、サーバーは2,896バイト送信しているので、シーケンス番号は3717860718〜3717863614となっています。しかし喪失した128,872バイトには足りないため、9行目でクライアントは再びsackを送信しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717863614, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0
サーバはクライアントから受信した確認応答番号3717863614からsackで通知された3717989590まで再送する必要があるとわかります。
その後再送とsackの送信を繰り返し、36行目でようやく喪失したすべてのパケットの再送を終えます。tcpdumpの出力では次のようにシーケンス番号が表示されています。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717979454:3717989590, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136
シーケンス番号3717989590まで送信していることがわかります。
すべての再送を終えたため、クライアントはパケット喪失から回復した直後に受信した6行目のパケットへの確認応答をする必要があります。
以下は6行目でサーバから受信したパケットです。この直前までパケットを喪失していました。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896
上記のパケットへの応答を37行目でクライアントがサーバへ送信しています。シーケンス番号3717992486に対して確認応答番号3717992486を返しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717992486, win 3403, options [nop,nop,TS val 344023 ecr 4051072696], length 0
38行目から通常のデータ転送を再開しています。これがsackによる再送のやり取りです。
まとめ
パケット解析をするためにはツールの使い方はもちろんの事、TCP/IPや解析しようとしているプロトコルの知識も必要となってきます。一番の勉強方法は良質な書籍を熟読する事です。もっともオススメなTCP/IP関連の書籍を紹介します。
¥2,178
(2021/01/23 03:46:27時点 Amazon調べ-詳細)
更に上を目指すならば応用編にチャレンジしてみて下さい。
¥4,180
(2021/01/23 12:21:50時点 Amazon調べ-詳細)
TCP/IPの基礎は年月を経ても変わる物ではないので、基礎から固めておけば必ず役に立ちます。
おすすめのパケットキャプチャ関連書籍
解析ツールの使い方やパケットキャプチャの手法について学びたければ、次の書籍がおすすめです。
¥2,950
(2021/01/23 05:00:08時点 Amazon調べ-詳細)
もしくは次の書籍もおすすめです。
- パケットキャプチャ入門 第3版 (LANアナライザWireshark活用術)
- 実践 パケット解析 第2版 ―Wiresharkを使ったトラブルシューティング
- 絶対わかる!コマンド&パケットキャプチャー超入門(日経BPムック) (日経BPムック)
tcpやudp、icmpやarpなどを指定できます。複数のプロトコルを指定したい場合は「or」を使います。
- tcp or udp
- tcp
ホストを指定する
hostコマンドを使用すると、送信元や送信先のホストを指定できます。
- host 192.168.2.1
- host 192.168.2.1 or 192.168.2.100
ネットワークを指定する
netコマンドを使用すると、送信元や送信先のネットワークを指定できます。
- net 192.168.2.0/24
ポート番号を指定する
portコマンドを使用すると、送信元や送信先のポート番号を指定できます。
- port 80
方向を指定する
今まで列挙したコマンドは送信元や送信先に関わらずマッチします。src/dstコマンドを使用すると、方向を指定できます。andやorを組み合わせると、より詳細にマッチさせる事ができます。
- src host 192.168.2.1
- dst host 192.168.2.200 and port 80
- src net 192.168.2.0/24 and dst host 172.16.31.1 and “(port 80 or 8080)”
TCPセッションフラグを指定する
SYNやFIN、RSTなどTCPセッションフラグの値を指定できます。
ビット演算子の&(アンド)で特定のビットが立っているか調べます。次の例はRSTフラグが立っているパケットにマッチします。
- “tcp[tcpflags] & tcp-rst != 0”
次の例はRSTもしくはFINフラグが立っているパケットにマッチします。
- “tcp[tcpflags] & (tcp-rst|tcp-fin) != 0”
特定の範囲の値を指定する
IPヘッダーのnバイト目が○である、とかTCPヘッダーのnバイト目が○以上である、といった指定ができます。
次の例は、TCPヘッダーの先頭から14バイト目から2バイトの値(TCP WINDOW)が40(0x28)であるパケットにマッチします。
- “tcp[14:2] == 40”
- “tcp[14:2] == 0x28”
次の例はTCPヘッダーの先頭から14バイト目から2バイトの値が40未満のパケットにマッチします。
- “tcp[14:2] < 40”
tcpdumpコマンドオプション
よく使うオプションを紹介します。
-n ホスト名を解決させない
-nn ホスト名の解決に加えてプロトコル名やポート番号も解決させない
-i <インタフェース名> 受信するインタフェースを指定する
-w <ファイル名> 受信パケットをpcap形式で保存するファイル名を指定する
-s <受信サイズ> 受信サイズを指定する
-S シーケンス番号を絶対値で表示する
-t タイムスタンプを表示しない
-tt タイムスタンプを整形せずに表示する
-ttt 直前に受信した時刻からの経過時間を表示する
-tttt 現在の日付と時刻を整形して表示する
-ttttt パケット受信を開始した時刻からの経過時間を表示する
-x パケットを16進数でダンプする
-X パケットを16進数でダンプし、併せてパケットの内容をアスキー表示させる
-v 詳細表示モードにする
-vv 更に詳細な表示モードにする
-vvv 最も詳細な表示モードにする
-e イーサネットヘッダーも表示する
-r <ファイル名> pcap形式で保存したファイルを読み込む
-c <カウント数> カウント数のパケットを受信したらtcpdumpを終了する
-C <サイズ> MB単位でローテーションするサイズを指定する
-W <個数> ファイルをローテーションする個数を指定する
キャプチャファイルのローテーション
キャプチャファイルを保存する領域のサイズが限られている際、ローテーションするサイズと個数を指定する事によって解決できます。
たとえばキャプチャするファイルサイズの上限を100MBにしたければ次のようにします:
- tcpdump -W 1 -C 100
こうすると、キャプチャファイルが100MBに達すると新たにファイルが作られる事なく同一ファイル名でローテーションします。稀にしか再現しない障害などを調査する目的で延々とキャプチャを続けなければならない場面で役に立ちます。
TCPの解析例
パケット解析するためには、パケットの構造を熟知している必要があります。

3ステップハンドシェーク(3ウェイハンドシェーク)
TCPは次の手順で3ステップハンドシェークによる接続を確立させます。
- クライアントからサーバーへSYNを送信する
- サーバーがクライアントへSYN+ACKを送信する
- クライアントがサーバーへACKを送信する
次の例は、yahoo.co.jpへHTTP接続する様子をtcpdumpで受信した時の結果です。
1 2 3 4 5 6 7 8 9 10 11 12 |
IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [S], seq 3917004649, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1014815386 ecr 0,sackOK,eol], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [S.], seq 3111149831, ack 3917004650, win 14480, options [mss 1414,sackOK,TS val 2466821728 ecr 1014815386,nop,wscale 9], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111149832, win 4118, options [nop,nop,TS val 1014815574 ecr 2466821728], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [P.], seq 3917004650:3917005380, ack 3111149832, win 4118, options [nop,nop,TS val 1014815575 ecr 2466821728], length 730: HTTP: GET / HTTP/1.1 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005380, win 32, options [nop,nop,TS val 2466821906 ecr 1014815575], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], seq 3111149832:3111151234, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 1402: HTTP: HTTP/1.1 301 Moved Permanently IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [P.], seq 3111151234:3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 642: HTTP IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [F.], seq 3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821908 ecr 1014815575], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151876, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821907], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151877, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [F.], seq 3917005380, ack 3111151877, win 4096, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005381, win 32, options [nop,nop,TS val 2466821918 ecr 1014815585], length 0 |
マーキングしている1〜3行目が3ステップハンドシェークを行っている箇所です。
- クライアントからサーバーへSYNを送信(初期シーケンス番号 3917004649)
- サーバーがクライアントへSYN+ACKを送信(初期シーケンス番号 3111149831/確認応答番号 3917004650)
- クライアントがサーバーへACKを送信して接続完了(確認応答番号 3111149832)
コネクション切断
トラブルシューティングを行う場合は、TCPコネクションがどのように遷移するのか知っている必要があります。とても重要なことなので、rfc793から抜粋したTCPの遷移図を掲載します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
+---------+ --------- active OPEN | CLOSED | ----------- +---------+<--------- create TCB | ^ snd SYN passive OPEN | | CLOSE ------------ | | ---------- create TCB | | delete TCB V | +---------+ CLOSE | | LISTEN | ---------- | | +---------+ delete TCB | | rcv SYN | | SEND | | ----------- | | ------- | V +---------+ snd SYN,ACK / snd SYN +---------+ | |<----------------- ------------------>| | | SYN | rcv SYN | SYN | | RCVD |<-----------------------------------------------| SENT | | | snd ACK | | | |------------------ -------------------| | +---------+ rcv ACK of SYN / rcv SYN,ACK +---------+ | -------------- | | ----------- | x | | snd ACK | V V | CLOSE +---------+ | ------- | ESTAB | | snd FIN +---------+ | CLOSE | | rcv FIN V ------- | | ------- +---------+ snd FIN / snd ACK +---------+ | FIN |<----------------- ------------------>| CLOSE | | WAIT-1 |------------------ | WAIT | +---------+ rcv FIN +---------+ | rcv ACK of FIN ------- | CLOSE | | -------------- snd ACK | ------- | V x V snd FIN V +---------+ +---------+ +---------+ |FINWAIT-2| | CLOSING | | LAST-ACK| +---------+ +---------+ +---------+ | rcv ACK of FIN | rcv ACK of FIN | | rcv FIN -------------- | Timeout=2MSL -------------- | | ------- x V ------------ x V snd ACK +---------+delete TCB +---------+ ------------------------>|TIME WAIT|------------------>| CLOSED | +---------+ +---------+ |
それでは、先ほど掲載したtcpdumpの結果を再掲載します。マーキングした箇所がTCPコネクションの切断を行っている箇所です。
1 2 3 4 5 6 7 8 9 10 11 12 |
IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [S], seq 3917004649, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1014815386 ecr 0,sackOK,eol], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [S.], seq 3111149831, ack 3917004650, win 14480, options [mss 1414,sackOK,TS val 2466821728 ecr 1014815386,nop,wscale 9], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111149832, win 4118, options [nop,nop,TS val 1014815574 ecr 2466821728], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [P.], seq 3917004650:3917005380, ack 3111149832, win 4118, options [nop,nop,TS val 1014815575 ecr 2466821728], length 730: HTTP: GET / HTTP/1.1 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005380, win 32, options [nop,nop,TS val 2466821906 ecr 1014815575], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], seq 3111149832:3111151234, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 1402: HTTP: HTTP/1.1 301 Moved Permanently IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [P.], seq 3111151234:3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821907 ecr 1014815575], length 642: HTTP IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [F.], seq 3111151876, ack 3917005380, win 32, options [nop,nop,TS val 2466821908 ecr 1014815575], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151876, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821907], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [.], ack 3111151877, win 4054, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0 IP 192.168.2.9.63382 > 182.22.59.229.80: Flags [F.], seq 3917005380, ack 3111151877, win 4096, options [nop,nop,TS val 1014815585 ecr 2466821908], length 0 IP 182.22.59.229.80 > 192.168.2.9.63382: Flags [.], ack 3917005381, win 32, options [nop,nop,TS val 2466821918 ecr 1014815585], length 0 |
順に追ってみましょう。
- 8行目:クライアントがFINを送信して「FIN-WAIT-1」へ遷移する。
- 9行目:FINを受信したサーバーはACK送信して「CLOSE WAIT」へ遷移する。クライアントはサーバーからACKを受信して「FIN WAIT-2」へ遷移する。
- 10行目:サーバーがFINを送信して「LAST ACK」へ遷移する。
- 11行目:FINを受信したクライアントはFIN+ACKを送信して「TIME WAIT」へ遷移する。
- 12行目:サーバーはFIN+ACKを受信して「CLOSED」へ遷移する。クライアントはタイムアウトして「CLOSED」へ遷移する。
選択確認応答(sack)
従来の累積確認応答はパケットを受信するごとに確認応答を返す、というやり取りを行っていました。この方法は信頼性があるのですが、やり取りが多くなるため効率が悪くなってしまいます。そこで、スライディングウィンドウというものを利用することになりました。これは簡単にいうと受信バッファが空いている間は確認応答を待たなくても連続して送信して良い、というものです。ここでいう受信バッファというのはTCP Windowサイズのことです。スライディングウィンドウは高速通信環境ではスループットを高めてくれますが、途中でパケットを喪失すると最後に確認応答したところからやり直す必要があります。また、高遅延な通信環境ではスループットの低下が顕著になります。
そこで、喪失したパケットだけ再送信して効率化を高めましょう、という発想から生まれたのが選択確認応答(sack)です。
それでは実際に再送している様子をtcpdumpで観察してみましょう。ちょっと長いので、スマートフォンでは見づらいかも知れません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3354, options [nop,nop,TS val 342395 ecr 4051066186], length 36 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3408, options [nop,nop,TS val 342447 ecr 4051066186], length 36 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [P.], seq 1766368136:1766368172, ack 3717859270, win 3408, options [nop,nop,TS val 342499 ecr 4051066186], length 36 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717859270:3717860718, ack 1766368136, win 303, options [nop,nop,TS val 4051072656 ecr 342395], length 1448 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717860718:3717863614, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 2896 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717863614, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717863614:3717867958, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 4344 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717867958, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717867958:3717869406, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 1448 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717869406, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717869406:3717873750, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 4344 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717873750, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717873750:3717880990, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 7240 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717880990, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717880990:3717888230, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 7240 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717888230, win 3373, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717888230:3717896918, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 8688 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717896918, win 3316, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717896918:3717907054, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717907054, win 3250, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717907054:3717943254, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 36200 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717943254, win 3022, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717943254:3717950494, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 7240 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717950494, win 3127, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717950494:3717954838, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 4344 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717954838, win 3097, options [nop,nop,TS val 344022 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717954838:3717966422, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 11584 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717966422, win 3394, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717966422:3717967870, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 1448 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717967870, win 3408, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717967870:3717979454, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 11584 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717979454, win 3394, options [nop,nop,TS val 344023 ecr 4051072696,nop,nop,sack 1 {3717989590:3717992486}], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717979454:3717989590, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717992486, win 3403, options [nop,nop,TS val 344023 ecr 4051072696], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717992486:3718022894, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 30408 IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3718022894, win 3298, options [nop,nop,TS val 344024 ecr 4051072696], length 0 IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3718022894:3718031582, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 8688 |
順を追ってsackによる再送の様子を説明します。少し長くなりますがパケットキャプチャの結果と併せて見てください。
5行目でクライアントは確認応答番号として3717860718を送信しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656], length 0
そのため次にクライアントが受信するべきシーケンス番号は3717860718のはずですが、6行目で受信したシーケンス番号は3717989590です。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896
3717989590 – 3717860718は128,872ですから、128,872バイトを5行目と6行目の間に喪失した事になります。
クライアントはパケットの喪失をここで検知しました。
そして喪失した部分を埋めるために、クライアントは7行目でsackを送信します。シーケンス番号3717989590以前のパケットを喪失したため再送する必要がある事をsackで伝えています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717860718, win 3408, options [nop,nop,TS val 344022 ecr 4051072656,nop,nop,sack 1 {3717989590:3717992486}], length 0
このsackにより、サーバーはクライアントから受信した確認応答番号3717860718からsackで通知された3717989590までの128,872バイトを再送する必要があるとわかります。
8行目からサーバーは最初に喪失したシーケンス番号3717860718のパケットを再送します。tcpdumpの出力では次のようにシーケンス番号が表示されています。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717860718:3717863614, ack 1766368136, win 303, options [nop,nop,TS val 4051072695 ecr 342395], length 2896
このとき、サーバーは2,896バイト送信しているので、シーケンス番号は3717860718〜3717863614となっています。しかし喪失した128,872バイトには足りないため、9行目でクライアントは再びsackを送信しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717863614, win 3408, options [nop,nop,TS val 344022 ecr 4051072695,nop,nop,sack 1 {3717989590:3717992486}], length 0
サーバはクライアントから受信した確認応答番号3717863614からsackで通知された3717989590まで再送する必要があるとわかります。
その後再送とsackの送信を繰り返し、36行目でようやく喪失したすべてのパケットの再送を終えます。tcpdumpの出力では次のようにシーケンス番号が表示されています。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717979454:3717989590, ack 1766368136, win 303, options [nop,nop,TS val 4051072696 ecr 342395], length 10136
シーケンス番号3717989590まで送信していることがわかります。
すべての再送を終えたため、クライアントはパケット喪失から回復した直後に受信した6行目のパケットへの確認応答をする必要があります。
以下は6行目でサーバから受信したパケットです。この直前までパケットを喪失していました。
IP 192.168.2.251.22 > 192.168.2.8.46463: Flags [.], seq 3717989590:3717992486, ack 1766368136, win 303, options [nop,nop,TS val 4051072694 ecr 342395], length 2896
上記のパケットへの応答を37行目でクライアントがサーバへ送信しています。シーケンス番号3717992486に対して確認応答番号3717992486を返しています。
IP 192.168.2.8.46463 > 192.168.2.251.22: Flags [.], ack 3717992486, win 3403, options [nop,nop,TS val 344023 ecr 4051072696], length 0
38行目から通常のデータ転送を再開しています。これがsackによる再送のやり取りです。
まとめ
パケット解析をするためにはツールの使い方はもちろんの事、TCP/IPや解析しようとしているプロトコルの知識も必要となってきます。一番の勉強方法は良質な書籍を熟読する事です。もっともオススメなTCP/IP関連の書籍を紹介します。
更に上を目指すならば応用編にチャレンジしてみて下さい。
TCP/IPの基礎は年月を経ても変わる物ではないので、基礎から固めておけば必ず役に立ちます。
おすすめのパケットキャプチャ関連書籍
解析ツールの使い方やパケットキャプチャの手法について学びたければ、次の書籍がおすすめです。
もしくは次の書籍もおすすめです。
- パケットキャプチャ入門 第3版 (LANアナライザWireshark活用術)
- 実践 パケット解析 第2版 ―Wiresharkを使ったトラブルシューティング
- 絶対わかる!コマンド&パケットキャプチャー超入門(日経BPムック) (日経BPムック)