TCPDUMPの出力を見てみよう

いかがですか。結構めんどくさいですね。 理論だけでは頭がいたくなってきます(私もそうです)。

実は、私もTCPについてはほとんど覚えておらず、必要となったときに書籍を 参考にしながらパケットを追いかけるということをしています。では、 さっそく実例としてtcpdump の出力を追いかけてみましょう。例として、Windows NT にログインして Netscape Communicator を起動したときのパケットの流れを見てみます。

ちょっとその前に予備知識として、私が今使用している PC(Windows NT 4.0)でどんなコネクションが張られているかを、 netstatコマンドで見てみましょう。

C:\>netstat -a

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    hotta:1030             0.0.0.0:0              LISTENING
  TCP    hotta:1035             0.0.0.0:0              LISTENING
  TCP    hotta:135              0.0.0.0:0              LISTENING
  TCP    hotta:135              0.0.0.0:0              LISTENING
  TCP    hotta:1438             0.0.0.0:0              LISTENING
  TCP    hotta:1440             0.0.0.0:0              LISTENING
  TCP    hotta:1482             0.0.0.0:0              LISTENING
  TCP    hotta:1511             0.0.0.0:0              LISTENING
  TCP    hotta:1512             0.0.0.0:0              LISTENING
  TCP    hotta:1516             0.0.0.0:0              LISTENING
  TCP    hotta:1517             0.0.0.0:0              LISTENING
  TCP    hotta:59630            0.0.0.0:0              LISTENING
  TCP    hotta:1025             0.0.0.0:0              LISTENING
  TCP    hotta:1025             localhost:1030         ESTABLISHED
  TCP    hotta:1030             localhost:1025         ESTABLISHED
  TCP    hotta:1034             0.0.0.0:0              LISTENING
  TCP    hotta:1034             www.hoge.co.jp:nbsession  ESTABLISHED
  TCP    hotta:137              0.0.0.0:0              LISTENING
  TCP    hotta:138              0.0.0.0:0              LISTENING
  TCP    hotta:nbsession        0.0.0.0:0              LISTENING
  TCP    hotta:nbsession        remotcsl1.hoge.co.jp:2100  ESTABLISHED
  TCP    hotta:1438             notes.hoge.co.jp:1352  ESTABLISHED
  TCP    hotta:1440             exp5800.hoge.co.jp:1352  ESTABLISHED
  TCP    hotta:1482             www.hoge.co.jp:ftp  CLOSE_WAIT
  TCP    hotta:1510             PCNT-BACKUP:nbsession  TIME_WAIT
  TCP    hotta:1511             www.hoge.co.jp:80  CLOSE_WAIT
  TCP    hotta:1512             www.hoge.co.jp:80  CLOSE_WAIT
  TCP    hotta:1516             www.hoge.co.jp:80  CLOSE_WAIT
  TCP    hotta:1517             www.hoge.co.jp:80  CLOSE_WAIT
  UDP    hotta:1035             *:*                    
  UDP    hotta:135              *:*                    
  UDP    hotta:59630            *:*                    
  UDP    hotta:nbname           *:*                    
  UDP    hotta:nbdatagram       *:*                    

左の項目から、プロトコル/自分のアドレス/相手側のアドレス/接続状態です。

  1. アドレス

    「hotta」とか「www.hoge.co.jp」とかいうのはホスト名 (すなわちIPアドレス)です。相手側アドレスが 0.0.0.0 は、 来るものは拒まず(どこから接続されてもよい)ということで、 自分自身がサーバとして動作していることを示します。

    相手側のホスト名が localhost (自分自身)となっているところも ありますね。この場合、サーバとクライアントが同一のマシン内で 動作していることを示しています。

    ところで、プロトコルがUDPの場合は、相手側のアドレスは'*'(全部OK) だし、接続状態のフィールドもありませんね。これは、UDPでは コネクションという概念がないからです。単に、突然UDPの該当 ポート番号のパケットが送られてきたら、それを受信するための アプリケーションが現在生きているよということを示すだけです。

  2. ポート番号

    アドレスのうち、コロン(:)の右側がTCP/UDPのポート番号です。 ただし、このうち %SYSTEMROOT%system32\drivers\etc\services に記載があるものについては「ポート名(サービス名)」 に変換されています。nbxxxxはNetBIOS(Microsoft Networkが使っている、 TCP/UDPのさらに上位のプロトコル)関連です。www.hoge.co.jp の右側にある80番は、かの有名なhttp(Hiper Text Transfer Protocol --- Webで使われる上位プロトコル)ですが、これは servicesファイルには記載されていないようです。

  3. 接続状態

    主に以下のものがあります。

    TCP STATE
    名称意味
    LISTENINGサーバとして、クライアントからの接続を待機中
    ESTABLISHEDコネクション確立状態(通信中)
    CLOSE_WAITコネクション終了待ち
    TIME_WAITコネクション終了後

    本当はもっとたくさんの状態があるのですが、ここらあたりの 理論は複雑で私もよく理解できません。もっと詳しく知りたい方は、 RFCJ -- RFC ならびに Internet Draft の日本語化文書集積/提供のページ でTCP関連のRFCを探したり、 linuxを入手して、 そのカーネルソースのTCP部分(tcp.c)を読んだりしてみなければ ならないでしょう。

では、いよいよTCPDUMPの出力です。これはLinux上で実行したので、 ポート番号80は'www'として表示されています。


hostname:~# tcpdump host hotta and port www
11:26:59.113561 hotta.1036 > server2.www: S 120396:120396(0) win 8192  (DF)
11:26:59.113561 server2.www > hotta.1036: S 1610721549:1610721549(0) ack 120397 win 31744 
11:26:59.113561 hotta.1036 > server2.www: . ack 1 win 8760 (DF)
11:26:59.473561 hotta.1036 > server2.www: P 1:313(312) ack 1 win 8760 (DF)
11:26:59.483561 server2.www > hotta.1036: P 1:173(172) ack 313 win 31744 (DF)
11:26:59.623561 hotta.1036 > server2.www: . ack 173 win 8588 (DF)
11:26:59.813561 hotta.1036 > server2.www: P 313:671(358) ack 173 win 8588 (DF)
11:26:59.813561 server2.www > hotta.1036: P 173:345(172) ack 671 win 31744 (DF)
11:26:59.923561 hotta.1036 > server2.www: . ack 345 win 8416 (DF)
11:27:14.803561 server2.www > hotta.1036: F 345:345(0) ack 671 win 31744
11:27:14.803561 hotta.1036 > server2.www: . ack 346 win 8416 (DF)

TCPDUMPは多くのプロトコルをサポートしており、プロトコルごとに出力 フォーマットが違います。ここではTCPパケットのみを表示しています。 フォーマットを以下に示します。

TCPDUMP(TCP protocol) OUTPUT FORMAT
名称意味
時刻HH:MM:SS.マイクロ秒
送信元アドレスホスト名(またはIPアドレス).ポート番号
矢印>
宛先アドレスホスト名(またはIPアドレス).ポート番号:
フラグ S:SYN(コネクション確立要求)
P:PUSH(バッファリングせず、即時にデータを送るようTCPに要求)
F:FIN(コネクション開放要求)
R:RST(コネクション強制切断要求)
.:上記いずれのフラグビットも立っていない
シーケンス番号s1:s2(s3)(*1)
s1:新しいデータの最初のバイトに対する(バイト単位の)シーケンス番号
s2:(今までに送った最後のバイトに対するシーケンス番号)+1
s3:バイト数
ACKビットack:ビットが立っており、 次のフィールドがACK番号であることを示す(*2)
ACK番号(*2)
ウィンドウwin:次のフィールドがウィンドウサイズであることを示す
ウィンドウサイズ
フラグメント禁止(DF):フラグメント(パケット分割)禁止ビットON
mss次のフィールドがmssであることを示す(*3)
最大セグメントサイズmss(Max Segment Size): 最大パケット長をこのサイズに制限させる

では、順番に追いかけてみましょう。

  1. 3ウェイ・ハンドシェーク
    11:26:59.113561 hotta.1036 > server2.www: S 120396:120396(0) win 8192  (DF)
    

    [1行目]まず、hotta(クライアント)側からserver2(サーバ) 側にS(SYN)を送信し、コネクションの確立を要求しています。 1行目(と2行目)では、シーケンス番号に何か大きな数字が 入っていることに注意してください。ここではまだ実データが 発生していませんので、シーケンス番号中の送信バイト数は0です。 win 8192 により、hottaというマシン(=Windows NT 4.0の標準状態) では、受信バッファサイズが8KBであることがわかります。

    ここで、サーバ側のポートは www(http) となっていますが、 クライアント側のポートは 1036 などとなっていますね?

    services で定義されているポート(サービス名)というのは、

    「サーバがそのポートを開けて(対応するプログラムを起動して)、 接続を待っている」

    番号(およびそれにつけられた別名)のことをいいます。 一方クライアント側は、自分のプログラムがそのマシン内で識別 できさえすればいいので、一般的には

    「OSが、その時点で空いているポート番号のうちの1つを適当に割り振る」

    ようにプログラマが指示します。ということで、 1036 というのは特に意味のない数字です。

    ごちゃごちゃしてわかりにくいので上記の出力からは削除しましたが、 実は tcpdump を上記のオプションで起動したら、同時に 1036 ポートと 1037 ポートという2つのコネクションができていました。もちろん相手は server2.www です。つまり瞬間的には、

    1つのクライアント・マシンから2つのクライアントが同じサーバの 同じポートに

    コネクションを張っていたわけです。

    11:26:59.113561 server2.www > hotta.1036: S 1610721549:1610721549(0) ack 120397 win 31744 <mss 1460>
    

    [2行目]サーバは、1行目のシーケンス番号+1をACK番号として ACKを送信すると同時に、そのパケットのSYNビットを立てて、 クライアント側に対する下りのコネクション確立を要求します。 また、ウィンドウ・サイズによりサーバ側のバッファは約 32KB あることがわかり、mss により、1度に送信するデータ (最大パケットサイズ)を 1460 バイトに制限したい旨を クライアント側に伝えています。

    11:26:59.113561 hotta.1036 > server2.www: . ack 1 win 8760 (DF)
    

    [3行目]クライアントはACKを返し、下りのコネクション確立を 知らせます。ここでACK番号が1にリセットされているように見えます。

    (この部分は読者からのご指摘により修正しました)
    これは、大きなシーケンス番号を毎回出力するのはわずらわしいので、 最初のSYNセグメントだけは完全なシーケンス番号を表示して、 それ以降は最初の番号からのオフセット値で示すようにしているからです。 tcpdump の起動時に -S オプションをつけると、全てのセグメントについて 完全なシーケンス番号を出力します。

    ウィンドウサイズが 8760 - 8192 = 568 バイトほど増えていますが、 これは何でしょうね?

  2. データの送受信
    11:26:59.473561 hotta.1036 > server2.www: P 1:313(312) ack 1 win 8760 (DF)
    

    [4行目]クライアントからサーバに対して 312 バイトのデータを 送っていますが、この中身はこの出力からはわかりません。おそらく www(http)プロトコルにしたがって、あるWebページに関する何かの要求を 行っているんでしょう。tcpdumpにオプションをつければデータ部も 拾えますが、データ部の中身を解析するには、さらに上位のプロトコル (ここではhttp)の知識が必要となります。といっても、ほとんどは テキストベースでしょうから、意外と理解しやすいかもしれませんが。

    このシーケンス番号により、クライアントは 1 から 313 までの 312 バイトのシーケンスを発生させました。P(PUSH)フラグが立っていますが、 これは送信側でバッファリングを禁止したり、受信側でなるべく 速やかに受信データをアプリケーションに渡してね、という指定です。
    (この部分もご指摘により修正しました。)

    11:26:59.483561 server2.www > hotta.1036: P 1:173(172) ack 313 win 31744 (DF)
    

    [5行目]ACK番号により、サーバはクライアントから送信された 312 までのデータ(つまり全部)を受信できたことを示します。と同時に、 サーバ側から 172 バイトのデータを送信しています。たぶん クライアント側からの問い合わせに対する返答でしょう。

    6行目〜9行目も関しても同様です。 がんばって追いかけてみてください (もしそれだけの根気があれば、ですが(^^;)。

  3. コネクションの開放
    11:27:14.803561 server2.www > hotta.1036: F 345:345(0) ack 671 win 31744
    

    [10行目](Web)サーバは、アプリケーションレベルのやりとりが 終わった(たぶんアプリケーションがコネクションを閉じる操作をした) ので、F(FIN) ビットを立てて下りコネクションの開放要求をクライアント (ブラウザ)側に送ります。もはや送信データはないので送信バイト数は 0 です。

    この時のタイムスタンプが9行目より15秒ほど進んでいることに 気がつかれたでしょうか?これは Web サーバ(Apache Web Server) 自体の設定で、ページの送信が完了しても、15秒間はそのコネクションを 保持するようになっているからです。こうしておくことにより、 ブラウザの画面を見ているユーザが、すぐにどこかをクリックして、 新たにサーバに対して要求を行った場合、サーバは即時に情報を 返すことができるようになっています。

    11:27:14.803561 hotta.1036 > server2.www: . ack 346 win 8416 (DF)
    

    [11行目]クライアントはサーバに対して FIN に対する ACK を返します。受信した実データはないにもかかわらず、ACK 番号はシーケンス番号 + 1 となっています。これは FIN を受信した旨を、 サーバに対して明示的に教えるためでしょう。

    チャプチャ(パケットの盗聴 --- 言葉が悪いな(-_-;))したデータは ここまでなのですが、本当はこの後クライアント側からも FIN が出て、 それに対するサーバ側からの ACK で一件落着となるべきのような気がします。 netstat の出力にあった CLOSE_WAIT というのは、この片方のコネクション のみがクローズされた状態をいうのではないのかしらん。実験してみれば いろいろ分かるんでしょうけど、さすがにそこまで私も暇ではないので(^^;、 時間と環境と好奇心が許す方は試してみてください。

これで、TCP/IP入門はとりあえずお開きにしたいと思いますが、 こういった情報も載せて欲しいということがあれば、ご遠慮なく ゲストブック に書き込んでみてください。 ひょっとしたら対応するかもしれません。