python + dpkt で pcap解析 - 1.読み込みから解析開始まで
Posted on 2012/05/11(Fri) 00:24 in technical
以前から小規模ではあるが、pythonでパケット分析をするためのモジュールdpkt(http://code.google.com/p/dpkt/)を使用している。
元々dokuwikiの方には少しだけ書いているのだが、整理がてらblogにも書いてみる。
まずはこの2つ。
- *.pcapファイルの読み込み
- 読み込んだバイナリデータの簡単な解析
ソース見れば分かる人はBitbucketへどうぞ。
windows、Linuxのいずれも使い方は変わらないはずだ。
手元の環境は windows XP/7 + Python 2.7.3 だが、好きにすればいいだろう。
dpkt自体は、
easy_install dpkt
でインストールする方法と、
http://code.google.com/p/dpkt/ からダウンロードしてきて
python setup.py config python setup.py install
でインストールする方法がある。
dpkt自体には若干信用出来ない部分もあるため、改修を加える必要に迫られるかもしれない。
その場合は、後者の方法で書き換えたほうが実害が少ない...ように思うが、それも個人の好みかもしれない。
さて、丁度いい例題が思い浮かばないが、適当に動くコードを見繕ってみる。
解析対象には、 wireshark wikiから拝借したpcapファイル を使おう。
pcapファイルを読み込んで、先頭パケットから最後のパケットまで、「フレームNo」「時間(1970/01/01 00:00:00.00からの経過時間)」「フレーム長(FCSの有無はpcapファイルに依存する)」を表示するだけのコード。
# -*- 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ファイルに含まれるIP Flow(EthernetType/SrcAddress/DstAddressの3-tuple)を分類して、その転送量を表示するように書いてみる。
# -*- 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.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) としてバイナリデータのパースを開始すると、可能な範囲でデコードが行われる。
その後の処理で、
ip = eth.data src = socket.inet_ntoa(ip.src)
のようにして、 ip.src に即座にアクセス出来るのは、既にパースが完了しているからで、この場合の ip.src は、 eth.data.src のようにしてもアクセス出来る。
とりあえず読み込みから初歩解析まで。
一からのパケット生成、ファイルへの書き出しまでは後日。