dpkt
pcap

dpktを使ってPCAPファイルを連結してみた

FUJITSU Advent Calendar 2017 part2 の20日目の記事です。
(注意)この記事は個人の見解であり、所属する会社、組織を代表するものではありません。

前提

常にファイルが追加され続けるPCAPファイルを一つの連続したファイルとして読み込ませたい。

例えばtsharkの -b オプションを指定した場合など、
複数のPCAPファイルが常に生成され続ける状態で、
先頭のファイルから連続してPCAPのデータを処理したい場合を考える。
(要はPCAPファイルの区切りで処理を中断させたくない)

解決方法

Pythonのdpktモジュールを用いて
入力にファイル名一覧のファイル、出力にPCAPファイルとするプログラムを作成した。
下記の dpkt_merge_pcap.py に相当する
https://github.com/t-umeno/dpkt_merge_pcap
https://github.com/t-umeno/dpkt_merge_pcap/blob/master/dpkt_merge_pcap.py

使い方

pip install dpkt
./dpkt_merge_pcap.py [-l input_pcap_file_list] [-o output_pcap_file]

要は-l PCAPファイル名一覧のファイル -o PCAPファイル出力先 を指定する。
オプションを指定しないと標準入力からファイル名一覧を読み込み、
標準出力にPCAPファイルを出力する。

解説

#!/usr/bin/python

import getopt, sys
import dpkt,socket

dpkt等の必要なモジュールを取り込む。

def usage():
    print "dpkt_merge_pcap [-l input_pcap_file_list] [-o output_pcap_file]"

-h オプション指定時やオプション誤り時に使用方法(usage)を表示する。

def main():
    input_pcap_file_list="/dev/stdin"
    output_pcap_file="/dev/stdout"

main()関数を開始し、
PCAPファイル名一覧のファイル名のデフォルト値を標準入力とし、
PCAPを出力するファイル名のデフォルト値を標準出力とする。

    try:
        opts, args = getopt.getopt(sys.argv[1:], "hl:o:", ["help", "input_pcap_file_list=", "output_pcap_file="])
    except getopt.GetoptError as err:
        # print help information and exit:
        usage()
        sys.exit(2)

-h オプション、-l input_pcap_file_listオプション、-o output_pcap_file以外の
オプションが指定されていれば、usageを表示し異常終了する。

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit(0)
        elif o in ("-l", "--input_pcap_file_list"):
             input_pcap_file_list = a
        elif o in ("-o", "--output_pcap_file"):
             output_pcap_file = a
        else:
            assert False, "unhandled option"

-h オプションが指定されていれば、usageを表示し正常終了する。
-l input_pcap_file_list オプションが指定されていれば、
PCAPファイル名一覧のファイルを input_pcap_file_list で指定したファイルとする。
-o output_pcap_file オプションが指定されていれば、
PCAPの出力先を output_pcap_file で指定したファイルとする。

    output_pcap = open(output_pcap_file,'wb')

PCAPの出力先に指定したファイルを書き込み目的で開く。

    pcw = dpkt.pcap.Writer(output_pcap)

dpktモジュールにPCAPの出力先を指定する。

    f = open(input_pcap_file_list)

PCAPファイル名一覧のファイルを開く。

    line = f.readline()
    line = line.rstrip()

PCAPファイル名一覧のファイルから1行読み込み、
読み込んだ1行の右端の空白や開業を削除する。

    if len(line) > 0:
        input_pcap = open(line,'rb')
        pcr = dpkt.pcap.Reader(input_pcap)
        for ts,buf in pcr:
            pcw.writepkt(buf,ts)
        input_pcap.close

①PCAPファイル名一覧のファイルから読み込んだ1行の長さが0でなければ、
読み込んだ1行に記載されたPCAPファイルを開いて読み込み、
読み込んだPCAPをPCAP出力先に指定したファイルに出力する。
読み込んだ1行に記載されたPCAPファイルを最後まで読み込んだら
読み込んだ1行に記載されたPCAPファイルを閉じる。
※PCAP出力先のファイルを閉じないことに注意する。

    while line:
        line = f.readline()
        line = line.rstrip()
        if len(line) == 0:
            continue
        input_pcap = open(line,'rb')
        pcr = dpkt.pcap.Reader(input_pcap)
        for ts,buf in pcr:
            pcw.writepkt(buf,ts)
        input_pcap.close

①をPCAPファイル名一覧の行数だけ繰り返す。

    f.close        
    output_pcap.close

PCAPファイル名一覧のファイルとPCAP出力先のファイルを閉じる。

if __name__ == '__main__':
    main()

main()関数を呼び出す。