読者です 読者をやめる 読者になる 読者になる

tom__bo’s Blog

情報系学生が筋トレしたり、筋トレしたり筋トレしたことを書くブログ。もはやダイアリー

tcpdump(8)の使い方

Linux Network

コマンドラインからパケットをキャプチャする場合の定番コマンド。
ネットワークインタフェースを指定してそこを流れるパケットをキャプチャしてくれる。 指定しない場合はメイン(?)のインタフェースになる。

たいてい管理者権限が必要。以降の例は全てsuperuserで実行したもの。

基本的な実行

まずはコマンド単体で全てのパケットを表示。

# tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s31f6, link-type EN10MB (Ethernet), capture size 262144 bytes
23:51:39.123157 IP buffalo.setup.48275 > 192.168.11.5.ftp: Flags [S], seq 4008159661, win 5840, options [mss 1460,sackOK,TS val 98194259 ecr 0,nop,wscale 1], length 0
23:51:39.124203 IP 192.168.11.5.15148 > buffalo.setup.domain: 37386+ PTR? 5.11.168.192.in-addr.arpa. (43)
23:51:39.152584 IP buffalo.setup.domain > 192.168.11.5.15148: 37386 NXDomain* 0/1/0 (109)
23:51:39.153063 IP 192.168.11.5.33842 > buffalo.setup.domain: 1070+ PTR? 1.11.168.192.in-addr.arpa. (43)
23:51:39.159265 IP buffalo.setup.domain > 192.168.11.5.33842: 1070* 1/0/0 PTR buffalo.setup. (70)
23:51:40.628933 IP 192.168.11.5.48078 > 192.30.253.125.https: Flags [.], ack 3996890997, win 245, options [nop,nop,TS val 4845696 ecr 1359955710], length 0
23:51:40.629524 IP 192.168.11.5.43592 > buffalo.setup.domain: 45774+ PTR? 125.253.30.192.in-addr.arpa. (45)
23:51:40.662384 IP buffalo.setup.domain > 192.168.11.5.43592: 45774 NXDomain 0/1/0 (113)
^C
8 packets captured
8 packets received by filter
0 packets dropped by kernel

1行目にコマンドの実行環境がでていてlistenしているインタフェース、link-type, キャプチャーサイズがわかる。 インタフェースを指定しなかったが、enp0s31f6というethernetのインタフェースが自動で選択された。

それ以降はキャプチャしたパケットが1行ずつに出力されていく。

時刻 プロトコル 送信元[.port] > 送信先[.ポート]: プロトコルごとの情報

が表示されている。

-vを指定することでより詳細なフィールドごとの情報がcsvっぽい微妙な形式で取得できる。

# tcpdump -v
tcpdump: listening on enp0s31f6, link-type EN10MB (Ethernet), capture size 262144 bytes
00:01:36.863991 IP (tos 0x0, ttl 64, id 32793, offset 0, flags [DF], proto TCP (6), length 296)
    192.168.11.5.45322 > 52.222.202.217.https: Flags [P.], cksum 0xcc7f (incorrect -> 0x4362), seq 3260976468:3260976712, ack 1997117091, win 1444, options [nop,nop,TS val 4994754 ecr 1197629794], length 244
00:01:36.864054 IP (tos 0x0, ttl 64, id 32794, offset 0, flags [DF], proto TCP (6), length 98)
    192.168.11.5.45322 > 52.222.202.217.https: Flags [P.], cksum 0xcbb9 (incorrect -> 0x1d96), seq 244:290, ack 1, win 1444, options [nop,nop,TS val 4994754 ecr 1197629794], length 46
00:01:36.864424 IP (tos 0x0, ttl 64, id 22469, offset 0, flags [DF], proto UDP (17), length 73)
    192.168.11.5.6692 > buffalo.setup.domain: 55500+ PTR? 217.202.222.52.in-addr.arpa. (45)

ファイルに出力する(wオプション)ときは-v or -vvすることでキャプチャしたパケット数を表示してくれる。

インタフェースの選択

ipコマンド等で確認しても良いが、–list-interfaces(-D) オプションでキャプチャ可能なインタフェースを確認できる。

# tcpdump -D
1.enp0s31f6 [Up, Running]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]
4.bluetooth0 (Bluetooth adapter number 0)
5.nflog (Linux netfilter log (NFLOG) interface)
6.nfqueue (Linux netfilter queue (NFQUEUE) interface)
7.usbmon1 (USB bus number 1)
8.usbmon2 (USB bus number 2)

指定は[-i インタフェース]。
どれでも良い(全て)場合は2番にあるように[-i any]

パケットの生データ表示

16進数出力

-xオプションで16進数表示。
-xxでリンク層まで16進数表示。

# tcpdump icmp -x
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s31f6, link-type EN10MB (Ethernet), capture size 262144 bytes
01:18:23.927582 IP 192.168.11.5 > tm-in-f147.1e100.net: ICMP echo request, id 27243, seq 1, length 64
    0x0000:  4500 0054 5fd9 4000 4001 40de c0a8 0b05
    0x0010:  6cb1 6193 0800 8b06 6a6b 0001 4f3a bc58
    0x0020:  0000 0000 2a27 0e00 0000 0000 1011 1213
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
    0x0050:  3435 3637
01:18:23.970620 IP tm-in-f147.1e100.net > 192.168.11.5: ICMP echo reply, id 27243, seq 1, length 64
    0x0000:  45c0 0054 0000 0000 2b01 f4f7 6cb1 6193
    0x0010:  c0a8 0b05 0000 9306 6a6b 0001 4f3a bc58
    0x0020:  0000 0000 2a27 0e00 0000 0000 1011 1213
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233
    0x0050:  3435 3637

ASCII出力

# tcpdump icmp -A
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s31f6, link-type EN10MB (Ethernet), capture size 262144 bytes
01:20:00.041672 IP 192.168.11.5 > tm-in-f106.1e100.net: ICMP echo request, id 27292, seq 1, length 64
E..T].@.@.C.....l.aj...Yj....:.X....}....................... !"#$%&'()*+,-./01234567
01:20:00.085315 IP tm-in-f106.1e100.net > 192.168.11.5: ICMP echo reply, id 27292, seq 1, length 64
E..T....+.. l.aj.......Yj....:.X....}....................... !"#$%&'()*+,-./01234567

両方

# tcpdump icmp -X
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s31f6, link-type EN10MB (Ethernet), capture size 262144 bytes
01:20:37.488224 IP 192.168.11.5 > tm-in-f103.1e100.net: ICMP echo request, id 27316, seq 1, length 64
    0x0000:  4500 0054 f39e 4000 4001 ad44 c0a8 0b05  E..T..@.@..D....
    0x0010:  6cb1 6167 0800 4371 6ab4 0001 d53a bc58  l.ag..Cqj....:.X
    0x0020:  0000 0000 f272 0700 0000 0000 1011 1213  .....r..........
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
    0x0050:  3435 3637                                4567
01:20:37.528357 IP tm-in-f103.1e100.net > 192.168.11.5: ICMP echo reply, id 27316, seq 1, length 64
    0x0000:  45c0 0054 0000 0000 2b01 f523 6cb1 6167  E..T....+..#l.ag
    0x0010:  c0a8 0b05 0000 4b71 6ab4 0001 d53a bc58  ......Kqj....:.X
    0x0020:  0000 0000 f272 0700 0000 0000 1011 1213  .....r..........
    0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
    0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
    0x0050:  3435 3637                                4567

パケットのフィルタリング

全てのパケットをキャプチャすると大量の出力になってしまうので、用途によって必要なパケットに絞る。 これにはexpressionを用いて、expression上でtrueになったものがキャプチャされる。 expressionの文法が若干謎(というよりpcap-filterのマニュアルにあるプリミティブしか受け付けない?)なため、よくSyntax errorと怒られる。

shellでバックスラッシュをつけるようなメタ文字はシングルクオートでくくればよい。 以下はよく使う絞り込みの対象

ホスト

(src/dst) host ホスト名

ex) tcpdump host 192.168.1.1
ex) tcudump src host www.google.com

IPアドレス(&サブネット)

(src/dst) net net/len ネットワークアドレス/サブネットマスクの長さ

ex) tcpdump net 192.168.11.0/24

ポート

(src/dst) port ポート番号

ex) tcpdump port 80

プロトコル

proto プロトコル

ex) tcpdump proto arp
## プロトコルがtcp,udp,icmpのいずれかであればprotoは省略可
pex) tcpdump icmp

方向(送信・受信)

一部のプリミティブ(host, port, net等)でdst,srcをexpressionの頭につけることで指定可能だが、hostやnetの前に方向(src|dst)をつけた場合、そのhost,netに対する方向を指定することになる。

例)
tcpdump src host 192.168.1.1
## 192.168.1.1を発信元とするパケットにフィルタリング

tcpdumpする端末を中心にパケットを見て行く時は、[-Q in|out|inout] のオプション指定でやったほうが単純にその端末に対する受信か送信なのでわかりやすい。 ただ、tcpdump自体に流れるパケットを削減できているわけではないようで、capturedとfileteredのパケット数がずれる。

ファイルへの読み書き

書き込み

-w (ファイル名)でファイルにパケットのバイナリをファイルに出力できる。

  • -Z ユーザ名: そのユーザの権限でファイルを作成
  • -v: -wと同時にこれをつけるとキャプチャしたパケット数がターミナル上に表示される
  • -C ファイルサイズ(MB単位): ファイルサイズより大きくなったら次のファイルを作成する

読み込み

ファイルに保存したデータはバイナリデータなので、バイナリエディタで開いてごりごり読むか “-r ファイル名"で読み込む。

ここで再度expressionによるフィルタリングが可能。

パケットを取りこぼさない工夫

ある程度トラフィックが多くなると、tcpdumpを停止した時に出力の最後に以下のようにパケットの取りこぼしが通知される。

108 packets captured
90 packets received by filter
18 packet dropped by kernel

この問題は-wオプションをつけて、バイナリデータをファイルに吐き出すことで解決した。 バイナリデータなので、tailコマンド等で見ることは出来ないが、取りこぼしがないことが大事。 とにかく標準出力のような–immediate-modeでない方法で出力をするのが良い様子。

-nで名前解決の停止、-Bでバッファサイズの拡張を試したが、どれほど効果があるかは疑問で、-wするだけで十分だった。

参考