Ubuntu Weekly Recipe

第367回Ubuntuでネットワークトラフィックを視覚化する

PCを使ううえでインターネットをはじめとするネットワーク機能は欠かせません。ネットワーク上ではさまざまなプロトコルやサービスに応じたパケットやフレームを機器間でやりとりしています。そこで今回はそんなネットワークのトラフィックの中身を見るために定番の、tcpdumpとWiresharkの基本的な使い方について紹介します。

Ubuntuなら常にインストールされているtcpdump

tcpdumpはlibpcapを利用したネットワークトラフィックをキャプチャ・表示するツールです。Ubuntuのstandardタスクに属しているため、普通のUbuntuやそのフレーバーであれば、常にインストールされているツールでもあります。

とりあえず実際に実行してみましょう。

$ sudo tcpdump -c 10

おそらくいろんなホストとの通信メッセージが表示されるはずです。⁠-c 10」は10パケット受信したら終了と言うオプションで、これがないとCtrl-Cを入力するまで延々とパケット情報を表示します。

出力の先頭フィールドは時刻です。その後ろについては、パケット種別によってフォーマットが異なります。たとえばARPパケットなら、問い合わせ内容と問い合わせ元のアドレスを表示します。

01:41:00.281097 ARP, Request who-has 192.168.10.3 tell 192.168.10.10, length 28
01:41:00.312383 ARP, Reply 192.168.10.3 is-at b8:27:eb:12:30:70, length 460

上記だと192.168.10.10から192.168.10.3のMACアドレスを問い合わせ、その結果が返ってきていることがわかります。

IPパケットであれば「送信元 > 送信先」のあとに、その内容を解析して概要を表示しています。

01:39:00.666424 IP 192.168.10.4.ssh > 192.168.10.10.54012:
    Flags [P.], seq 692251127:692251519, ack 2792381807, win 1810,
    options [nop,nop,TS val 932541213 ecr 44643234], length 392
01:39:00.666458 IP 192.168.10.10.54012 > 192.168.10.4.ssh:
    Flags [.], ack 392, win 1436,
    options [nop,nop,TS val 44643486 ecr 932541213], length 0

上記は192.168.10.4と192.168.10.10の間でssh通信が行われているときの様子です。

フィルタリング機能

tcpdumpは特にオプションを指定していない場合、そのホストが接続されているネットワーク上のパケットを表示します。しかしながら、その量は膨大であるため、必要な情報はすぐに流れてしまいます。そのため、tcpdumpには強力なパケットフィルタリング機能が存在します。

「-i」オプションはキャプチャするネットワークインターフェースを指定します。

$ sudo tcpdump -i eth0

「-P」オプションは受信パケットか送信パケットかを制約します。inなら受信パケットのみ、outなら送信パケットのみ、inoutなら送受信両方です。

$ sudo tcpdump -P in

なおこの「-P」オプションは14.04までのtcpdumpでのみ有効です。14.10で採用している4.6.2以降のtcpdumpは「-Q」オプションに名前が変わっているので注意してください。

オプションでは基本的なルールしか設定できませんが、コマンドの末尾にpcap準拠のフィルタリングルールを記載できます。パケットをフィルタする場合はこちらを使うほうが多いでしょう。

特定のホストに関連するパケットだけを表示したい場合はhostフィルタを使用します。また、各フィルタはandやor、notなどで連結可能です。

ホスト名emaの通信だけを表示
$ sudo tcpdump host ema

ホスト名emaと、miiもしくはriiとの通信を表示
$ sudo tcpdump host ema and \( mii or rii \)

ホスト名emaの通信のうち、taroに関連するものだけを除外
$ sudo tcpdump host ema and not taro

IPアドレスでの指定も可能
$ sudo tcpdump host 192.168.0.1

特定のポートの通信だけを表示する場合は、portフィルタを使用します。ポート番号でも指定できますし、/etc/servicesに列挙されていれば名前を使うこともできます。さらに各フィルタは「dst」「src」を追加すると、宛先、送信元それぞれのポートに限定できますし、⁠tcp」「udp」などプロトコル指定も可能です。

zukaホストでポート番号5060に関連する通信だけを表示
$ sudo tcpdump host zuka and port 5060

ftpもしくはftp-dataのポート」が宛先になっている通信だけ表示
$ sudo tcpdump dst port ftp or ftp-data

sshポートの通信のうちTCPパケットのみ表示
$ sudo tcpdump tcp port ssh

oiホストから送られるIPv4のブロードキャストパケットのみ表示
$ sudo tcpdump ip broadcast and src host oi

その他にもいろいろなルールを指定できます。詳しいことはpcap-filterのマニュアルを参照してください。

出力のカスタマイズ

tcpdumpは特に指定しなければ、各パケットの概要を1行で表示します。ただし、サポートしていないプロトコルについては送信元と宛先、データサイズぐらいしか表示されません[1]⁠。

しかし実際にtcpdumpを使用する場合は、サポートしていないプロトコルの、具体的なパケットの内容を表示したいこともあるでしょう。そこでtcpdumpには便利な出力オプションがいくつも存在します。

「-x」オプションを使うと、データの内容を16進表記で出力してくれます。バイナリデータのやり取りを行う通信を確認したい時に便利でしょう。⁠-A」オプションならASCII表示にしてくれますので、HTMLなどのテキストデータを確認できます。⁠-X」だとhdコマンドのように16進とASCIIをならべて表示してくれます。

下記は80番ポートの通信を監視しつつ、Webブラウザーでhttp://gihyo.jp/にアクセスした時の抜粋です。3ウェイ・ハンドシェイクのあとに、HTTP/1.1のGETメソッドの通信が行われていることがわかります[2]⁠。

$ sudo tcpdump -i wlan0 -X -c 5 port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:20:26.638452 IP 192.168.10.10.59296 > gihyo.jp.http: Flags [S],
        ...
02:20:26.658487 IP gihyo.jp.http > 192.168.10.10.59296: Flags [S.],
        ...
02:20:26.658544 IP 192.168.10.10.59296 > gihyo.jp.http: Flags [.],
        ...
02:20:26.658697 IP 192.168.10.10.59296 > gihyo.jp.http: Flags [P.],
        0x0000:  4500 0299 f66d 4000 4006 22ac c0a8 0a0a  E....m@.@.".....
        0x0010:  31d4 22bf e7a0 0050 a593 4639 fb5c 6ec2  1."....P..F9.\n.
        0x0020:  8018 00e5 5959 0000 0101 080a 02b2 b058  ....YY.........X
        0x0030:  1c35 4b9b 4745 5420 2f20 4854 5450 2f31  .5K.GET./.HTTP/1
        0x0040:  2e31 0d0a 486f 7374 3a20 6769 6879 6f2e  .1..Host:.gihyo.
        0x0050:  6a70 0d0a 5573 6572 2d41 6765 6e74 3a20  jp..User-Agent:.
        0x0060:  4d6f 7a69 6c6c 612f 352e 3020 2858 3131  Mozilla/5.0.(X11
        0x0070:  3b20 5562 756e 7475 3b20 4c69 6e75 7820  ;.Ubuntu;.Linux.
        0x0080:  7838 365f 3634 3b20 7276 3a33 362e 3029  x86_64;.rv:36.0)

他にも「-n」オプションを付けるとホスト名やプロトコルをそれぞれIPアドレス、ポート番号のまま表示します。⁠-N」オプションはドメイン名のうちホスト名部分のみを表示します。

「-e」オプションを付けると、Ethernetフレームの情報などデータリンク層のヘッダーも一緒に表示します。16進ダンプしたい場合は「-x」「-X」をそれぞれ「-xx⁠⁠、⁠-XX」に変更してください。

ファイルへの保存とファイルからの再生

tcpdumpはネットワークトラフィックの様子をほぼリアルタイムで表示しますが、デバッグ目的のためにあとから見返したいこともあるでしょう。また、キャプチャ時はフィルタリングルールを設けずに、関連しそうなパケットをとりあえず全部取得し、その後tcpdumpで仕分けしたい場合もあるはずです。

そんなときに便利なのが指定したファイルに保存する「-w」オプションです。

$ sudo tcpdump -i eth0 -w yano.pcap

tcpdumpはlibpcap形式のバイナリデータとしてパケットの内容を保存します。⁠-U」オプションとセットで利用すると、パケットを受信したら即座にファイルに保存します。一度保存すれば「-r」オプションで当時のトラフィックの様子を再度確認できます。

$ sudo tcpdump -r yano.pcap port 80

上記の「port 80」のように、通常と同様のフィルタリングルールを利用可能です。

ちなみにUbuntuの場合、AppArmorによって拡張子が「.pcap」のファイルのみtcpdumpの「-r」オプションに渡すことが可能になっています[3]⁠。⁠yano.log」「yano.dat」では「Permission denied」になるので注意してください。

pcapファイルが大きくなりすぎないように、⁠-C」オプションを使って上限サイズを設けて、ローテーションさせることも可能です。⁠-G」オプションを使うと、指定した時間ごとにローテーションします。どちらのオプションも「-W」オプションでローテーションの数を制限できます。⁠-z」オプションを使うと、ローテーションのタイミングで任意のスクリプトやコマンドを実行できますので、継続的なログを取得する際に利用すると良いでしょう。

tcpdumpは個々のパケットで65535バイトを超えるデータは切り捨てています。このサイズは「-s」オプションで変更できますが「-s 0」とすることで、パケットすべてを保存できます。pcapファイルに保存する場合はこのオプションも併せて付けておけば、あとからの追跡調査の場合に取りこぼしがなくなります。

GUIによるアナライザーWireshark

Wiresharkはマルチプラットフォームに対応した、GUI付きのネットワークプロトコルアナライザーです。Linux版のWiresharkはtcpdumpと同様にバックエンドにlibpcapを利用してネットワークトラフィックをキャプチャします。洗練されたわかりやすいUIを備えているので、キャプチャしたパケットの解析はtcpdumpよりも使いやすいです。Ubuntuでもwiresharkパッケージをインストールすれば導入できます。

図1 Wiresharkなら数多くのプロトコルに対応した表示をしてくれる
図1 Wiresharkなら数多くのプロトコルに対応した表示をしてくれる

ところでネットワークトラフィックをキャプチャするには管理者権限が必要です。tcpdumpの場合はsudo付きで起動しましたが、wiresharkの場合は以下の3つから選べます。

  1. pkexecを使って管理者権限で起動する
  2. wiresharkグループに属してdumpcapを利用する
  3. tcpdumpやdumpcapで出力したpcapファイルを読み込む

1.はWiresharkを管理者権限で起動する方法です。polkitの設定が必要なうえ、GUIアプリを管理者権限で起動することに抵抗があるかもしれません。

2.はインストール時の質問にYesと答えたときに行われる設定です。インストール時にNoと答えた場合でも、以下のコマンドで再設定できます。

$ sudo dpkg-reconfigure wireshark-common

wiresharkグループが作成されますので、次のコマンドでユーザーをそのグループに追加します。

$ sudo adduser $USER wireshark

追加後は一度ログインしなおしてください。さらにdumpcapコマンドもインストールしておきます。

$ sudo apt-get install pcaputils

これで一般ユーザーで起動したWiresharkでも、ネットワークトラフィックをキャプチャできるようになっているはずです。この方法だと管理者権限は必要ありませんが、wiresharkグループに属しているユーザーであれば誰でもキャプチャできるようになる点は注意が必要です。

3.はWiresharkを解析のみに利用し、キャプチャするコマンドは別途用意する方法です。libpcap形式であればtcpdumpを、pcapng形式であればdumpcapコマンドを利用します。この方法はWiresharkがインストールされていないようなマシンでキャプチャしたデータも利用できるため、普段はこの方法でも充分でしょう。

WiresharkのCUI版TShark

WiresharkのCUI版がTSharkです。Debianパッケージの場合はwiresharkパッケージとは分離されて、tsharkパッケージとして提供されてます。

tsharkのキャプチャ機能はtcpdumpのそれと大した違いはありません。tsharkで便利なのは、CUIでもWiresharkと同等のディスプレイフィルタ機能やパケットの詳細表示機能が使えると言うことでしょう。

たとえばtsharkでpcapファイルを読み込むと次のように表示されます。

$ tshark -r rinko.pcap
1   0.000000 192.168.10.10 -> 153.121.51.184 TCP 74 6041180 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=47313761 TSecr=0 WS=128
2   0.010867 153.121.51.184 -> 192.168.10.10 TCP 74 8060411 [SYN, ACK] Seq=0 Ack=1 Win=14480 Len=0 MSS=1414 SACK_PERM=1 TSval=2539409277 TSecr=47313761 WS=64
3   0.010925 192.168.10.10 -> 153.121.51.184 TCP 66 6041180 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=47313764 TSecr=2539409277
4   0.011019 192.168.10.10 -> 153.121.51.184 HTTP 763 GET / HTTP/1.1
5   0.022089 153.121.51.184 -> 192.168.10.10 TCP 66 8060411 [ACK] Seq=1 Ack=698 Win=15936 Len=0 TSval=2539409288 TSecr=47313764

このうち4番目のフレームの詳細を表示するには次のようにframe.numberでフィルタリングします。

$ tshark -r rinko.pcap -V -Y 'frame.number==4'
Frame 4: 763 bytes on wire (6104 bits), 763 bytes captured (6104 bits)
    Encapsulation type: Ethernet (1)
...
Hypertext Transfer Protocol
    GET / HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET / HTTP/1.1\r\n]
            [GET / HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]

パケットデータ部分を表示する場合は、⁠-x」オプションを使用します。

$ tshark -r rinko.pcap -x -Y 'frame.number==4'
0000  a4 12 42 3e f8 3c 64 80 99 70 2c a4 08 00 45 00   ..B>.<d..p,...E.
0010  02 ed 26 74 40 00 40 06 79 b3 c0 a8 0a 0a 99 79   ..&t@.@.y......y
0020  33 b8 eb fb 00 50 e7 d0 d5 14 a0 7d 80 2f 80 18   3....P.....}./..
0030  00 e5 ab d5 00 00 01 01 08 0a 02 d1 f3 64 97 5c   .............d.\
0040  4f 7d 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31   O}GET / HTTP/1.1
0050  0d 0a 48 6f 73 74 3a 20 6d 75 73 61 6e 69 2e 6a   ..Host: musani.j
0060  70 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 4d   p..User-Agent: M
0070  6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 58 31 31 3b   ozilla/5.0 (X11;
0080  20 55 62 75 6e 74 75 3b 20 4c 69 6e 75 78 20 78    Ubuntu; Linux x
0090  38 36 5f 36 34 3b 20 72 76 3a 33 36 2e 30 29 20   86_64; rv:36.0)

他にもtsharkであれば「-z」オプションを使って、パケットの内容に応じた統計情報を表示することも可能です。

プログラミング言語でも

今回紹介したtcpdump/Wireshark/TSharkはいずれもLinux版はlibpcapのフロントエンドです。もし特定の条件のパケットを受信したときにもっと柔軟に処理を行いたい場合は、libpcapを使ったプログラムを作成すると言う方法もあります。

libpcapを直接使うにはC言語を使う必要がありますが、libpcapには各プログラミング言語のバインディングが存在します。たとえばPythonならPyCapなどがありますし、Goであればgopacketにpcapというパッケージが存在するようです。よって、好みの言語を使って開発することはそれほど難しくはないでしょう。

おすすめ記事

記事・ニュース一覧