tcpdump を使ってみる

プログラミング4の授業で「StalkingExplorer」を作りました。
その時にみんながどのサイトにアクセスしているのかを監視できたら面白い!
ってことで、tcpdumpを使って実現させました。

その前にtcpdumpとは何者か?
tcpdumpとは…

  1. ネットワーク上に流れるパケットをモニタリングする。
  2. オプションとして条件式を指定すれば,取得したい情報にフィルタリングしてパケットを取得できる。
  3. 通常は,root権限をもつ場合にのみ利用可能。


と言うことで、パケットの中を覗いて監視してみようかと思いました。



参考ページ:
tcpdumpを使いこなす! | Think IT(シンクイット)
tcpdumpの使い方 - TECHNERD::INIT
tcpdumpでプロトコルを解析してみよう


今回は自分のローカル環境で作業します。
とりあえず、tcpdumpってコマンドを打ってみた。

$tcpdump
tcpdump: WARNING: en0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en0, link-type EN10MB (Ethernet), capture size 65535 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

あれ?なにも出ないけど、、、、 (o・ω・o)…ムニュ?
$ifconfig をしてみると、

en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 
                …
	inet 192.168.25.38 netmask 0xffffff00 broadcast 192.168.25.255

どうやら今使っているIPはen1の方らしい。
[-i interface]オプションを使って、en1を見るようにする。

$tcpdump -i en1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en1, link-type EN10MB (Ethernet), capture size 65535 bytes
15:23:51.475302 IP 192.168.25.2.panasas > 239.255.255.250.ssdp: UDP, length 326
15:23:51.577514 IP 192.168.25.2.panasas > 239.255.255.250.ssdp: UDP, length 326
15:23:51.680142 IP 192.168.25.2.panasas > 239.255.255.250.ssdp: UDP, length 335
15:23:51.782497 IP 192.168.25.2.panasas > 239.255.255.250.ssdp: UDP, length 335
15:23:51.815904 IP 192.168.25.38 > 133.13.254.26: GREv1, call 13208, seq 19353, ack 19987, length 98: compressed PPP data
15:23:51.821377 IP 192.168.25.38.36189 > 111.221.77.144.40035: UDP, length 153
(省略)

14 packets captured
76 packets received by filter
0 packets dropped by kernel

これで通信が見れました (*´∀`*)b.:゚+♪
さて、次はパッケットの中身を見ます。
[-X]オプションを使います。パケットの内容を16進数に加えてASCII文字でも出力。
[-s snaplen]オプションを使い、取得するパッケットの量を変更。(多いほうがいいかとw)

$tcpdump -i en1 -Xs 1600
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en1, link-type EN10MB (Ethernet), capture size 1600 bytes
15:38:37.531348 IP 65.55.223.19.40017 > 192.168.25.38.49453: Flags [.], ack 3780585786, win 126, options [nop,nop,TS val 3402336726 ecr 28867385], length 0
	0x0000:  4500 0034 d9ed 4000 2b06 7bbd 4137 df13  E..4..@.+.{.A7..
	0x0010:  c0a8 1926 9c51 c12d 9d44 ea35 e157 293a  ...&.Q.-.D.5.W):
	0x0020:  8010 007e bb06 0000 0101 080a cacb 89d6  ...~............
	0x0030:  01b8 7b39                                ..{9
15:38:37.531426 IP 192.168.25.38.49453 > 65.55.223.19.40017: Flags [P.], seq 1:1170, ack 0, win 65535, options [nop,nop,TS val 28867824 ecr 3402336726], length 1169
	0x0000:  4500 04c5 f7a7 4000 4006 4472 c0a8 1926  E.....@.@.Dr...&
	0x0010:  4137 df13 c12d 9c51 e157 293a 9d44 ea35  A7...-.Q.W):.D.5
	0x0020:  8018 ffff b61c 0000 0101 080a 01b8 7cf0  ..............|.
	0x0030:  cacb 89d6 8667 7ada dffd 6e89 d6ed 4fb1  .....gz...n...O.
	0x0040:  c065 5c17 1e81 0cdb 6e3b adab 50f1 e6ca  .e\.....n;..P...
	0x0050:  c7fc 1653 931c 9577 375e cc84 7de8 2027  ...S...w7^..}..'

ふぅ…
これで誰がなにを見ているか確認できますね|д゚)チラッ
今回はどのWebサイトを見ているかを知りたいので、プロトコルの制限をします。
HTTPプロトコルを見たいので、port www を使います。
port 80 でもいけます。

$tcpdump -i en1 -Xs 1600 port www
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en1, link-type EN10MB (Ethernet), capture size 1600 bytes
15:43:34.650306 IP 192.168.25.38.50831 > i195090.ppp.asahi-net.or.jp.http: Flags [S], seq 1761015172, win 65535, options [mss 1460,nop,wscale 3,nop,nop,TS val 29163736 ecr 0,sackOK,eol], length 0
	0x0000:  4500 0040 4312 4000 4006 1d00 c0a8 1926  E..@C.@.@......&
	0x0010:  3d7d c35a c68f 0050 68f6 f584 0000 0000  =}.Z...Ph.......
	0x0020:  b002 ffff 3469 0000 0204 05b4 0103 0303  ....4i..........
	0x0030:  0101 080a 01bd 00d8 0000 0000 0402 0000  ................
15:43:34.902563 IP 192.168.25.38.50832 > i195090.ppp.asahi-net.or.jp.http:Flags [S], seq 4022165267, win 65535, options [mss 1460,nop,wscale 3,nop,nop,TS val 29163986 ecr 0,sackOK,eol], length 0
	0x0000:  4500 0040 063d 4000 4006 59d5 c0a8 1926  E..@.=@.@.Y....&
	0x0010:  3d7d c35a c690 0050 efbd 5f13 0000 0000  =}.Z...P.._.....
	0x0020:  b002 ffff 4318 0000 0204 05b4 0103 0303  ....C...........
	0x0030:  0101 080a 01bd 01d2 0000 0000 0402 0000  ................

HTTPプロトコルだけを取得出来ました( ´∀`)bグッ!
さて、次は…
クライアントがどのサイトアクセスしたのかを見たいので、、、パッケットの受信(src)ではなく、送信(dst)を見たい!!
[det]オプションを使えばおk。

$tcpdump -i en1 -Xs 1600 dst port www
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on en1, link-type EN10MB (Ethernet), capture size 1600 bytes
15:59:58.968358 IP 192.168.25.38.51016 > 59.106.194.36.http: Flags [S], seq 538349893, win 65535, options [mss 1460,nop,wscale 3,nop,nop,TS val 30144137 ecr 0,sackOK,eol], length 0
	0x0000:  4500 0040 5e25 4000 4006 0536 c0a8 1926  E..@^%@.@..6...&
	0x0010:  3b6a c224 c748 0050 2016 9145 0000 0000  ;j.$.H.P...E....
	0x0020:  b002 ffff ee58 0000 0204 05b4 0103 0303  .....X..........
	0x0030:  0101 080a 01cb f689 0000 0000 0402 0000  ................
15:59:59.007050 IP 192.168.25.38.51016 > 59.106.194.36.http: Flags [.], ack 2448420585, win 65535, options [nop,nop,TS val 30144175 ecr 4234612562], length 0
	0x0000:  4500 0034 971b 4000 4006 cc4b c0a8 1926  E..4..@.@..K...&
	0x0010:  3b6a c224 c748 0050 2016 9146 91ef eee9  ;j.$.H.P...F....
	0x0020:  8010 ffff a15c 0000 0101 080a 01cb f6af  .....\..........
	0x0030:  fc67 0f52                                .g.R
15:59:59.007209 IP 192.168.25.38.51016 > 59.106.194.36.http: Flags [.], seq 0:1402, ack 1, win 65535, options [nop,nop,TS val 30144175 ecr 4234612562], length 1402
	0x0000:  4500 05ae 6404 4000 4006 f9e8 c0a8 1926  E...d.@.@......&
	0x0010:  3b6a c224 c748 0050 2016 9146 91ef eee9  ;j.$.H.P...F....
	0x0020:  8010 ffff 20eb 0000 0101 080a 01cb f6af  ................
	0x0030:  fc67 0f52 4745 5420 2f63 6869 7061 3334  .g.RGET./chipa34
	0x0040:  2f32 3030 3830 3231 302f 3132 3032 3635  /20080210/120265
	0x0050:  3031 3833 2048 5454 502f 312e 310d 0a48  0183.HTTP/1.1..H

これで送信だけが見れます!
これでtcpdumpは一通り終わりです。
あとはここからパッケットを読み、サイトだけを抽出します。

$tcpdump -i en1 -Xs 1600 dst port www > tcpdump.dat 

tcpdump.dat に入れて、作業します。
今回は「誰が」って要素はいろいろと問題があると思ったので、その要素を除きます。

$grep "0x0"
grepを使い"0x0"が含まれるやつだけ抽出します。

$cat tcpdump.dat |grep "0x0"
	0x0000:  4500 0040 84c7 4000 4006 db4a c0a8 1926  E..@..@.@..J...&
	0x0010:  3d7d c35a c76a 0050 3629 b2a6 0000 0000  =}.Z.j.P6)......
	0x0020:  b002 ffff 3a6c 0000 0204 05b4 0103 0303  ....:l..........
	0x0030:  0101 080a 01ce 6f94 0000 0000 0402 0000  ......o.........
	0x0000:  4500 0034 88f3 4000 4006 d72a c0a8 1926  E..4..@.@..*...&
	0x0010:  3d7d c35a c76a 0050 3629 b2a7 95df f875  =}.Z.j.P6).....u
	0x0020:  8010 ffff fa80 0000 0101 080a 01ce 6fbf  ..............o.
	0x0030:  0705 ea22                                ..."
	0x0000:  4500 0354 eacf 4000 4006 722e c0a8 1926  E..T..@.@.r....&

次にパケットだけ抽出します。

$tr -s " " " "
スペースが連続する場合1つにする。(例:ho ge → ho ge)

$cut -f10 -d " "
スペースを区切りとして10番目にあるものを抽出する。
(例:1 2 3 4 5 6 7 8 9 10 → 10)

$cat tcpdump.dat |grep "0x0"| tr -s " " " " | cut -f10 -d " "
E..@..@.@..J...&
=}.Z.j.P6)......
....:l..........
......o.........
E..4..@.@..*...&
=}.Z.j.P6).....u
..............o.

E..T..@.@.r....&
=}.Z.j.P6).....u
..............o.
..."GET./~68user
/net/tcpdump.htm
l.HTTP/1.1..Host
:.x68000.q-e-d.n
et..User-Agent:.
Mozilla/5.0.(Mac
intosh;.Intel.Ma

パケットの部分だけ抽出ができました。
でもここままではhttpの部分が読み取りにくい。。。(;´∀`)
変な所で改行されているからなぁ〜。

$tr -d '\n'
改行を取り除く。

$sed 's/http:\/\//\n http:\/\//g'
httpで改行するようにする。
(置換:sed 's/◯◯◯/×××/g')

 E..<4.@.@.|s..0..^.B...P............;,...............(省略)
 http://tt-house.com/2011/09/mac-opencv-python.html..Accep(省略)
 http://tt-house.com/2011/09/mac-opencv-python.html..Accep(省略)
 http://tt-house.com/2011/09/mac-opencv-python.html..Accep(省略)
 http://view.atdmt.com/PPJ/iview/361875012/direct;w(省略)
 http://ad.yieldmanager.com/clk?3,eJydzVFvgjAQB.BPw(省略)

(MacBookでは\nが.nに置換された…どうしましょう)
とりあえず、サーバ側で出来たのでおkってことでwww
結果を見てみると、「..」の後は必要ないようですね。

$sed 's/\.\..*//'
「..」以下を削除。

$sed 's/)$//'
「)」以下を削除。

$cat tcpdump.dat |grep "0x0"| tr -s " " " " | cut -f10 -d " " |tr -d '\n'| sed 's/http:\/\//\n http:\/\//g'|sed 's/\.\..*//' |sed 's/)$//'
E
 http://www.google.com/bot.html
 http://live.nicovideo.jp
 http://travel.rakuten.co.jp/

これでURLだけ抽出完了!!
いよいよ最後です。

$sort
文字列を並び替えます。

$uniq
行の重複を消去。

$cat tcpdump.dat |grep "0x0"| tr -s " " " " | cut -f10 -d " " |tr -d '\n'| sed 's/http:\/\//\n http:\/\//g'|sed 's/\.\..*//' |sed 's/)$//'|sort|uniq
 http://live.nicovideo.jp
 http://travel.rakuten.co.jp/
 http://www.google.com/bot.html

以上!
これで完成です!!

※これを実際に組み込むといろいろと問題が有りそうなので、StalkingExplorerでは「/」の3番目以降は表示しない仕様にしています。

お疲れ様でした。