UNIX/Linuxの部屋 tcpdumpコマンドの使い方

TOP UNIX/Linuxの部屋 UNIX/Linuxコマンド一覧 用語集 新版 由来/読み方辞書 環境変数マニュアル Cシェル変数 システム設定ファイル システムコール・ライブラリ ネットワークプログラミングの基礎知識 クラウドサービス徹底比較・徹底解説




コマンド tcpdump ネットワーク上を流れるパケットを監視する このエントリーをはてなブックマークに追加

tcpdump コマンドは、ネットワーク上のデータやパケットの内容を確認するためのコマンドである。概要は http://X68000.q-e-d.net/~68user/net/tcpdump.html を参照。

一般的には tcpdump を使用するには root 権限が必要である (厳密に言うと、例えば FreeBSD では /dev/bpf* の読み込み権限があれば一般ユーザでも実行可能だが、デフォルトでは root しか読み込みができないように設定されている)。



tcpdump の出力を解説しよう。tcpdump はパケットの中身を単に表示するだけではなく、プロトコルに応じて適切な出力を行う。

TCP 編
以下は tcpdump を実行中に http://www.jp.FreeBSD.org/ を閲覧した際の出力である。
# tcpdump
02:45:33.633849 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
S 42054:42054(0) win 65535 <mss 1460,nop,wscale 1,nop,nop,timestamp 9425028 0> (DF)
02:45:33.650088 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
S 16252:16252(0) ack 42055 win 57344 <mss 1414,nop,wscale 0,nop,nop,timestamp 1935830307 9425028>
02:45:33.650167 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
. ack 1 win 32947 <nop,nop,timestamp 9425030 1935830307> (DF)
02:45:33.650877 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
P 1:19(18) ack 1 win 32947 <nop,nop,timestamp 9425030 1935830307> (DF)
02:45:33.764048 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
. ack 19 win 57482 <nop,nop,timestamp 1935830319 9425030>
02:45:33.764112 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
P 19:98(79) ack 1 win 32947 <nop,nop,timestamp 9425041 1935830319> (DF)
02:45:33.781163 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
P 1:365(364) ack 98 win 57482 <nop,nop,timestamp 1935830320 9425041>
02:45:33.781486 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
F 98:98(0) ack 365 win 32947 <nop,nop,timestamp 9425043 1935830320> (DF)
02:45:33.781522 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
F 365:365(0) ack 98 win 57482 <nop,nop,timestamp 1935830320 9425041>
02:45:33.781551 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
F 98:98(0) ack 366 win 32947 <nop,nop,timestamp 9425043 1935830320> (DF)
02:45:33.796105 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
F 365:365(0) ack 99 win 57482 <nop,nop,timestamp 1935830322 9425043>
02:45:33.796236 192.168.1.12.63342 > updraft3.jp.freebsd.org.http:
. ack 366 win 32947 <nop,nop,timestamp 9425044 1935830322> (DF)
02:45:33.796499 updraft3.jp.freebsd.org.http > 192.168.1.12.63342:
. ack 99 win 57482 <nop,nop,timestamp 1935830322 9425043>

1カラム目は時刻である。「02:45:33.633849」は「02時45分33.633849秒」を表す。

2カラム目は、送信元と送信先の ホスト名・ポート名である。例えば 1行目は、
  • パケットの送信元は 192.168.1.12、ポート番号は 63342
  • パケットの送信先は updraft3.jp.freebsd.org、ポートは http (ポート番号 80)
ということである。

ホスト名については、もし名前解決を行えればホスト名で、名前解決ができなければ IP アドレスでの表記になる。またポートについても、ポート番号が /etc/services に記載されていれば対応するサービス名を表示するが、記載されていなければポート番号をそのまま表示する。

上記の例では、192.168.1.12 は名前解決できなかったため IP アドレスで表示したが、updraft3.jp.freebsd.org については名前解決に成功したためホスト名で表示したわけである。同様にポート番号 63342 は /etc/services に記載されていなかったのでポート番号のまま表示したが、ポート番号 80 は /etc/services に記載されており、対応するサービス名が http であったため、サービス名を表示したということだ。

このホスト名・サービス名の自動変換を行わせたくない、つまり常に IP アドレスとポート番号をそのまま表示してほしい場合は -n オプションを使うとよい。

出力例があまりに繁雑なので、簡略化しよう。第一カラムのタイムスタンプを省略し、「192.168.1.12.63342」と「updraft3.jp.freebsd.org.http」をそれぞれ「C」(クライアント)「S」(サーバ) に置換し、桁数をあわせ、さらに末尾の timestamp を省略したものが以下の通りである。
C > S: S 42054:42054(0)           win 65535 <mss 1460,nop,wscale 1,nop,nop> (DF)
S > C: S 16252:16252(0) ack 42055 win 57344 <mss 1414,nop,wscale 0,nop,nop>
C > S: .                ack 1     win 32947 <nop,nop> (DF)
C > S: P 1:19(18)       ack 1     win 32947 <nop,nop> (DF)
S > C: .                ack 19    win 57482 <nop,nop>
C > S: P 19:98(79)      ack 1     win 32947 <nop,nop> (DF)
S > C: P 1:365(364)     ack 98    win 57482 <nop,nop>
C > S: F 98:98(0)       ack 365   win 32947 <nop,nop> (DF)
S > C: F 365:365(0)     ack 98    win 57482 <nop,nop>
C > S: F 98:98(0)       ack 366   win 32947 <nop,nop> (DF)
S > C: F 365:365(0)     ack 99    win 57482 <nop,nop>
C > S: .                ack 366   win 32947 <nop,nop> (DF)
S > C: .                ack 99    win 57482 <nop,nop>

  • フラグ (S・P・F などの項目)
TCP ヘッダの S (SYN), F (FIN), P (PUSH), R (RST) のビットが立っている場合、その頭文字が表示される。いずれのビットも立っていない場合は「.」(ドット) が表示される。それぞれのフラグは独立しているため、SYN と PUSH が立っていれば、「SP」という出力になる (SYN と PUSH が同時に立つものなのかどうかは知らない)。

  • シーケンス番号
シーケンス番号はデータの順序性を保証するための番号で、新規コネクションのたびに新しい値がランダムに決定される。tcpdump の表示では
42054:42054(0)
となっているが、これは
「開始シーケンス番号:終了シーケンス番号(TCP データ長)」
を表す。この例では、ランダムに決定されたシーケンス番号は 42054 で、データ長は 0、終了シーケンス番号は (データ長が 0 なので) 42054、となる。最初のパケットでは SYN フラグが立っているだけで、TCP データは含まれていないことに注意しよう。また、TCP ヘッダには開始シーケンス番号が記録されているが、終了シーケンス番号は記録されていない。単に tcpdump が「開始シーケンス番号 + TCP データ長」を計算し、終了シーケンス番号として表示してくれているだけである。

一方 2行目の、サーバからクライアントへの SYN+ACK のシーケンス番号は、
16252:16252(0)
という、先ほどの「42054」という値とは一切関係ない値になっている。クライアントとサーバのシーケンス番号は、完全に独立していることに注意しよう。

シーケンス番号のみに注目してみると、
C > S: 42054:42054(0)
S > C: 16252:16252(0)
C > S: 1:19(18)
C > S: 19:98(79)
S > C: 1:365(364)
となる。3行目以降はいきなり値が小さくなっているが、これは tcpdump が開始時のシーケンス番号との差分に計算しなおして、わかりやすく表示しているのである。よって、本当のシーケンス番号は
C > S: 42054:42054(0)
S > C: 16252:16252(0)
C > S: 42055:42073(18)
C > S: 42073:42152(79)
S > C: 16253:16617(364)
となる。このように実際のシーケンス番号を表示したい場合は -S オプションを付けるとよい。

  • ack
ACK は確認応答のこと。例えば「ACK 123」というのは
「シーケンス番号 122 番までは受け取ったから、次は 123 番から送ってね」
という意味である。

クライアント側のシーケンス番号と、サーバ側のシーケンス番号を混同しないように。上記の例で、クライアントのシーケンス番号に「C」、サーバのシーケンス番号に「S」を追加してみた。少しはわかりやすいだろうか。
C > S: C42054:42054(0)
S > C: S16252:16252(0) ack C42055
C > S: C1:19(18)       ack S1
C > S: C19:98(79)      ack S1
S > C: S1:365(364)     ack C19

  • ウィンドウサイズ
ウィンドウサイズを表す。TCP では、相手の ACK を受信してから次のデータを送信する。しかし、相手の ACK を待つのが無駄な場合がある。例えば、クライアントが web サーバにアクセスし、巨大なファイルを取得する場合などは、クライアントからの ACK を待たずにどんどんデータを送信したいところだ。

TCP にはウィンドウサイズという概念がある。簡単に言うと「自分はある程度のバッファを持っているので、ACK を待たずにどんどんデータを送っていいよ。ただし、バッファを越えない程度に送ってね」というものである。

このバッファの容量のことを「ウィンドウサイズ」と呼ぶ。tcpdump が「win 65535」と表示しているのがそれである。例を見るとわかるとおり、ウィンドウサイズはコネクション接続中でも刻々と変化するものである。意味合いとしては「あとこれだけバッファが残ってます」といったところか。
C > S: S 42054:42054(0)           win 65535
S > C: S 16252:16252(0) ack 42055 win 57344
C > S: .                ack 1     win 32947
C > S: P 1:19(18)       ack 1     win 32947
S > C: .                ack 19    win 57482
C > S: P 19:98(79)      ack 1     win 32947

なお、TCP ヘッダ中のウィンドウサイズの領域は 16 バイトしかないため、本来ならば最大 65535 までしか定義できないが、RFC 1323 にてウィンドウサイズを 2^n 倍して扱うことができる拡張がなされている。
C > S: S 42054:42054(0) win 65535 <mss 1460,nop,wscale 1,nop,nop> (DF)
の「wscale 1」がそれで、ウィンドウサイズは 2^1 倍した値として扱われる。

  • オプション
以下の例において、括弧内の部分がオプションである。
C > S: <mss 1460,nop,wscale 1,nop,nop> (DF)
S > C: <mss 1414,nop,wscale 0,nop,nop>
C > S: <nop,nop> (DF)
MSS とは Maximum Segment Size の略で、受け取り可能な TCP データの最大長を相手側に通知している。MSS には TCP ヘッダ長は含まないことに注意。TCP/IP においては、「IP ヘッダ長 + TCP ヘッダ長 + MSS」が MTU となる。

上記の例ではクライアントがサーバに「MSS は 1460 でよい?」と提示し、サーバが「1460 は大きすぎるので 1414 でお願い」と返事している。最終的に両者が「では MSS は 1414 でいきましょう」と合意したわけである。

ちなみに最初の 1460 は、Ethernet の MTU が 1500 で (ifconfig で確認するとよい)、1500 からIP ヘッダ (20 バイト) と TCP ヘッダ (20 バイト) を引くと 1460 になるためである。最終的に 1414 になってしまったのは、上記の環境では NTT のフレッツ ADSL を利用しており、フレッツ ADSL 内部の MTU が 1454 なため、MSS は 1454-20-20 = 1414 となったからである (より細かく言うと、一部のネットワークでは ICMP Type 3 (Destination Unreachable) Code 4 (Fragmentation Needed) を通さないため、フレッツ ADSL のルータが無理矢理 1414 に…という話になるが、長くなるので略)。

オプションの nop は、TCP のヘッダを 32 ビットの整数倍にそろえるためのパディングである。

  • DF
パケット分割が禁止されている (Don't fragment) IP データグラムには、末尾に「DF」と表示される。


DNS 編
以下は、tcpdump を実行中に http://www.jp.FreeBSD.org/ を閲覧した際に行われた、名前解決とその応答のパケットである。DNS サーバへの問い合わせについての詳細は、http://X68000.q-e-d.net/~68user/net/resolver-2.html を参照してほしい。
15:52:45.442411 192.168.1.12.49836 > 210.226.20.15.53: 21876+ AAAA? www.jp.freebsd.org. (36)
15:52:45.486764 210.226.20.15.53 > 192.168.1.12.49836: 21876* 1/3/5 AAAA[|domain]
15:52:45.487170 192.168.1.12.49837 > 210.226.20.15.53: 21877+ A? www.jp.freebsd.org. (36)
15:52:45.534757 210.226.20.15.53 > 192.168.1.12.49837: 21877* 1/3/5 A 211.14.6.244 (220)

送信先のポート番号は「53」となっている。これは /etc/services における
domain 53/udp #Domain Name Server
のことである。

1行目は AAAA レコードの照会、2行目はそれに対する応答、3行目は A レコードの照会、4行目はそれに対する応答である。まず、上記の出力からは以下のことが読み取れる。
  • まず、www.jp.FreeBSD.org の IPv6 アドレス (AAAA レコード) を DNS サーバ 210.226.20.15 に問い合わせ、IPv6 アドレスを得た。
  • 次に www.jp.FreeBSD.org の IPv4 アドレス (A レコード) を DNS サーバ 210.226.20.15 に問い合わせ、IPv4 アドレス 211.14.6.244 を得た。

「21876」「21877」は、識別子である (http://X68000.q-e-d.net/~68user/net/resolver-2.html#id 参照)。識別子の後の「+」は再帰照会を表し、「*」は Authoritative Answer (権威のある回答) を表す。「AAAA?」や「A?」の「?」は照会であることを表す。「1/3/5」は、回答レコード/権威レコード/追加情報レコード数がそれぞれ 1個・3個・5個であることを表す。括弧内の数字 (行末の (36) や (220) など) は、UDP データ長を表す。

ダンプ対象パケットの選択
tcpdump ではいろいろな表現でダンプ対象のパケットを選択することができる。以下の記述は引数の最後に記述すること (tcpdump -s 1600 port 80 は OK だが、tcpdump port 80 -s 1600 は NG)。

  • ip proto プロトコル
IPv4 データグラムのうち、指定したプロトコルのみダンプ対象とする。プロトコルは icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, tcp のいずれかを指定可能。ただし tcp・udp・icmp はキーワードでもあるため、エスケープしなければならない。
# tcpdump ip proto igmp
⇒ tcp・udp・icmp 以外はそのまま記述すればよいが…
# tcpdump ip proto \\tcp
# tcpdump ip proto '\tcp'
⇒ tcp・udp・icmp は上記のいずれかの書き方をしなければならない
# tcpdump tcp
⇒ なぜなら、この書き方と区別が付かないから (でも誤解を生じない文脈なら許容してほしいぞ)
  • tcp, udp, icmp
それぞれ TCP・UDP・ICMP のみをダンプ対象とする。例えば udp を指定することは、実際は「ip proto \\udp or ip6 proto \\udp」を指定するのと同じ。
  • host ホスト名 (または IP アドレス)
送信元または送信先が、指定されたホスト名または IP アドレスの場合、ダンプ対象とする。<li>src host ホスト名 (または IP アドレス)
送信元が、指定されたホスト名または IP アドレスの場合、ダンプ対象とする。
  • dst host ホスト名 (または IP アドレス)
送信先が、指定されたホスト名または IP アドレスの場合、ダンプ対象とする。
  • net ネットワーク
送信元または送信先が、指定されたネットワークに含まれる場合、ダンプ対象とする。ネットワークは「10」「10.0.1」「10.0.0.0/28」などと指定する。host と同様に、「src net ネットワーク」「dst net ネットワーク」で送信元・送信先の指定も可能。
  • port ポート番号 (またはサービス名)
送信元または送信先のポート番号が、指定されたポート番号またはネットワーク名の場合、ダンプ対象とする。http ならば 80 または http。pop3 ならば 110 または pop3 または pop-3。サービス名は /etc/services に記載されているものに限る。host と同様に、「src port ポート番号」「dst port ポート番号」で送信元・送信先の指定も可能。

オプション一覧
-l バッファリングしない。tcpdump の出力をパイプで他プログラムに渡す場合に使用する。
-n IP アドレスをそのまま表示する (ホスト名に変換しない)。また、ポート番号もそのまま表示する (サービス名に変換しない)
特に DNS サーバとのやりとりをダンプする際は、tcpdump 自身が行う名前解決と混ざってしまうので、-n オプションを付けることをお勧めする。
-x パケットの内容を 16進ダンプで出力する
192.168.1.12.63438 > updraft3.jp.freebsd.org.http: ...
4500 0034 23b5 4000 4006 7b58 c0a8 010c
d30e 06f4 f7ce 0050 2a11 555b 9d6b 22e1
8010 80b3 ee07 0000 0101 080a 00ae 1299
7380 adab
-X パケットの内容を 16進ダンプで出力し、さらに ASCII 文字を表示する。
192.168.1.12.63440 > updraft3.jp.freebsd.org.http: ...
0x0000   4500 0046 2615 4000 4006 78e6 c0a8 010c        E..F&.@.@.x.....
0x0010   d30e 06f4 f7d0 0050 f90c 7a6f ed2c 8e78        .......P..zo.,.x
0x0020   8018 80b3 90b8 0000 0101 080a 00ae 4478        ..............Dx
0x0030   7380 df87 4745 5420 2f78 7820 4854 5450        s...GET./xx.HTTP
0x0040   2f31 2e31 0d0a                                 /1.1..
-i モニタリングするネットワークインタフェースを指定。-i lo0 や -i ed0 や -i ppp など。
使用可能なネットワークインタフェースの一覧は ifconfig コマンドでわかる。
-s パケットから取り出すデータの長さ。
デフォルトでは -x や -X オプションについて先頭 68 バイトしか取得しない。1600バイト取得したい場合は -s 1600 とする。データを取りこぼしたくなければ、ifconfig でモニタリング対象のインタフェースの MTU を確認し、それより大きい値を指定すること。イーサネットであれば MTU は 1500 だが、ループバックアドレス (lo0 や lo など) は 4000 や 16000 など、比較的大きな値であることが多い。
-S 実際のシーケンス番号を表示する (初期値との差分で表示しない)
-t タイムスタンプを表示しない (第一カラムの 02:45:33.781551 のような表示を抑制する)
例:
192.168.1.12.63374 > updraft3.jp.freebsd.org.http: (略)
updraft3.jp.freebsd.org.http > 192.168.1.12.63374: (略)
192.168.1.12.63374 > updraft3.jp.freebsd.org.http: (略)
-tt タイムスタンプを UNIX 時間で表示する (1970年1月1日からの経過秒数 + マイクロ秒)
例:
1108840358.345089 192.168.1.12.63374 > updraft3.jp.freebsd.org.http: (略)
1108840358.361603 updraft3.jp.freebsd.org.http > 192.168.1.12.63374: (略)
1108840358.361680 192.168.1.12.63374 > updraft3.jp.freebsd.org.http: (略)
-ttt タイムスタンプを、直前の行との差分で表示する (マイクロ秒単位)
例:
000000 192.168.1.12.63392 > updraft3.jp.freebsd.org.http:
⇒ 最初に流れたパケットのタイムスタンプは必ず 0 になる
017365 updraft3.jp.freebsd.org.http > 192.168.1.12.63392:
⇒ 直前のパケットから 0.017365 秒経過
7. 013180 192.168.1.12.63392 > updraft3.jp.freebsd.org.http:
⇒ 直前のパケットから 7.013180 秒経過
>> Linuxオンラインマニュアル(man) Linux tcpdump(1)
>> FreeBSDオンラインマニュアル(man) FreeBSD tcpdump(1)