はじめに
以前から小規模ではあるが、pythonでパケット分析をするためのモジュールdpkt http://code.google.com/p/dpkt/ を使用している。
元々dokuwikiの方には少しだけ書いているのだが、整理がてらblogにも書いてみる。
今回は以下の2つの方法について紹介する。
*.pcap
ファイルの読み込み
- 読み込んだバイナリデータの簡単な解析
ソース見れば分かる人はBitbucketへどうぞ。 https://bitbucket.org/ainoniwa/dpkt-tutorial/
インストール
windows、Linuxのいずれも使い方は変わらないはずだ。
手元の環境は windows XP/7 + Python 2.7.3 だが、好きにすればいいだろう。
dpkt自体は、
でインストールする方法と http://code.google.com/p/dpkt/ からダウンロードしてきて
1
2
|
python setup.py config
python setup.py install
|
でインストールする方法がある。
dpkt自体には若干信用出来ない部分もあるため、改修を加える必要に迫られるかもしれない。
その場合は、後者の方法で書き換えたほうが実害が少ない…ように思うが、それも個人の好みかもしれない。
pcapファイルの読み込み
さて、丁度いい例題が思い浮かばないが、適当に動くコードを見繕ってみる。
解析対象には wireshark wikiから拝借したpcapファイル を使おう。
pcapファイルを読み込んで、先頭パケットから最後のパケットまで「フレームNo」「時間(1970/01/01 00:00:00.00からの経過時間)」「フレーム長(FCSの有無はpcapファイルに依存する)」を表示するだけのコード。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import dpkt
def main():
filename = u'C:\\dev\\pcap\\tcp-ecn-sample.pcap'
pcr = dpkt.pcap.Reader(open(filename,'rb'))
packet_count = 0
for ts,buf in pcr:
packet_count += 1
print packet_count, '. time: ', ts, 'Length:', len(buf)
if __name__ == '__main__':
main()
|
非常に短いが、その役割は果たされているはず。
pcap内のパケットの単純な解析
同じように、同pcapファイルに含まれるIP Flow(EthernetType/SrcAddress/DstAddressの3-tuple)を分類して、その転送量を表示するように書いてみる。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import dpkt
import socket
def main():
filename = u'C:\\dev\\pcap\\tcp-ecn-sample.pcap'
pcr = dpkt.pcap.Reader(open(filename,'rb'))
packet_count = 0
flow_list = {}
for ts,buf in pcr:
packet_count += 1
try:
eth = dpkt.ethernet.Ethernet(buf)
except:
print 'Fail parse FrameNo:', packet_count, '. skipped.'
continue
if type(eth.data) == dpkt.ip.IP:
ip = eth.data
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
flow_word = src + " to " + dst
if flow_list.has_key(flow_word):
flow_list[flow_word] += len(str(buf))
else:
flow_list[flow_word] = len(str(buf))
for k,v in flow_list.iteritems():
print k, ':', v, '[Byte]'
if __name__ == '__main__':
main()
|
実行結果
1
2
3
|
>>>
1.1.23.3 to 1.1.12.1 : 18695 [Byte]
1.1.12.1 to 1.1.23.3 : 92582 [Byte]
|
この結果は、wiresharkのConversationsと一致することが確認できるはずだ。
このような形で、pcapファイルを開き、そのバイナリデータを各プロトコルで扱いやすい形でパースして利用することが出来る。
注意したいのは dpkt.ethernet.Ethernet(buf)
としてバイナリデータのパースを開始すると、可能な範囲でデコードが行われる。
その後の処理で、
1
2
|
ip = eth.data
src = socket.inet_ntoa(ip.src)
|
のようにして ip.src
に即座にアクセス出来るのは、既にパースが完了しているから。
この場合の ip.src
は eth.data.src
のようにしてもアクセス出来る。
終わり
とりあえず読み込みから初歩解析まで。
一からのパケット生成、ファイルへの書き出しまでは後日。