LoginSignup
3
2

More than 5 years have passed since last update.

PcapファイルをMySQLに入れる

Last updated at Posted at 2018-01-23

PcapファイルMySQLに格納

TL;DR

大量のPcapファイルを効率的に扱いたい。
日付ごとのtableを作成しpcapをmysqlに入れる。
下記のコードはTCPのみです。

前提

  • ファイル名は<適当な名前>_year-month-day_HH:MM:SS.pcap
  • pythonからアクセスするためのユーザやデータベース

ファイル名からaccess_log_yyyymmddのtableを作成するため、get_day() 関数は適当に自分の環境に合わせて変更

コード

# -*- coding: utf-8 -*-
from glob import glob
import dpkt
import socket
from datetime import datetime, timedelta
import time
from collections import OrderedDict
from os.path import basename, splitext
import MySQLdb

def pcap2csv(file_name, proto="TCP"):
    def _bool2int(_bool_list):
        return [1 if row == True else 0 for row in _bool_list]

    def _uts2dt(ts):
        return datetime.strftime(datetime.fromtimestamp(ts), "%Y-%m-%d %H:%M:%S")

    def _ipheader(header, proto):
        src_ip = socket.inet_ntoa(header.src)
        dst_ip = socket.inet_ntoa(header.dst)
        header_len = header.hl
        ttl = header.ttl

        if (proto == "TCP") and (type(header.data) == dpkt.tcp.TCP):
            tcp = header.data
            src_port = tcp.sport
            dst_port = tcp.dport
            data_len = len(tcp.data)
            _bool_list = []
            _bool_list.append((tcp.flags & dpkt.tcp.TH_URG) != 0)
            _bool_list.append((tcp.flags & dpkt.tcp.TH_ACK) != 0)
            _bool_list.append((tcp.flags & dpkt.tcp.TH_PUSH) != 0)
            _bool_list.append((tcp.flags & dpkt.tcp.TH_RST) != 0)
            _bool_list.append((tcp.flags & dpkt.tcp.TH_SYN) != 0)
            _bool_list.append((tcp.flags & dpkt.tcp.TH_FIN) != 0)
            code_bit = _bool2int(_bool_list)
            window = tcp.win
            urg_p = tcp.urp
            seq_num = tcp.seq
            result = OrderedDict()
            result["yyyy-mm-dd hh:mm:ss"] = None
            result["src_ip"] = src_ip
            result["src_port"] = src_port
            result["dst_ip"] = dst_ip
            result["dst_port"] = dst_port
            result["header_len"] = header_len
            result["data_len"] = data_len
            result["ttl"] = ttl
            result["urg"] = code_bit[0]
            result["ack"] = code_bit[1]
            result["psh"] = code_bit[2]
            result["rst"] = code_bit[3]
            result["syn"] = code_bit[4]
            result["fin"] = code_bit[5]
            result["window"] = window
            result["urg_pointer"] = urg_p
            result["seq_number"] = seq_num
            return result
        """
        if (proto == "UDP") and (type(header.data) == dpkt.udp.UDP):
            udp = header.data
            src_port = udp.sport
            dst_port = udp.dport
            data_len = len(udp.data)
            result = {
                "yyyymmdd": None,
                "hh:mm:ss": None,
                "src_ip": src_ip,
                "src_port": src_port,
                "dst_ip": dst_ip,
                "dst_port": dst_port,
                "header_len": header_len,
                "data_len": data_len,
                "ttl": ttl,
            }
            return result

        if (proto == "ICMP") and (type(header.data) == dpkt.icmp.ICMP):
            icmp = header.data
            data_len = len(icmp.data)
            header_len = icmp.da
            result = {
                "yyyymmdd": None,
                "hh:mm:ss": None,
                "src_ip": src_ip,
                "dst_ip": dst_ip,
                "header_len": header_len,
                "data_len": data_len,
                "ttl": ttl,
            }
            return result
        """
        return None

    res = []
    pcap = dpkt.pcap.Reader(open(file_name, "rb"))
    for ts, buf in pcap:
        eth = dpkt.ethernet.Ethernet(buf)
        if type(eth.data) == dpkt.ip.IP:
             ip = _ipheader(eth.data, proto)
             if ip != None:
                 ip["yyyy-mm-dd hh:mm:ss"] = _uts2dt(ts)
                 res.append(ip.values())
    return res

class DB:
    def __init__(self):
        self.conn = MySQLdb.connect(host="localhost", port=3306, user="", passwd="", db="", charset="utf8")
        self.cur = self.conn.cursor()

    def create_table(self, day):
        sql = "create table access_log_%s(id INT AUTO_INCREMENT primary key, date datetime, src_ip varchar(255), src_port int, dst_ip varchar(255), dst_port int, header_len int, data_len int, ttl int, urg int, ack int, psh int, rst int, syn int, fin int, window int, urg_pointer varchar(255), seq_number bigint)" % day
        self.__execute(sql)

    def insert(self, day, vals):
        sql = "insert into access_log_%s(date,src_ip,src_port,dst_ip,dst_port,header_len,data_len,ttl,urg,ack,psh,rst,syn,fin,window,urg_pointer,seq_number) values(%s)" % (day, ",".join(["'%s'" % str(r) for r in vals]))
        self.__execute(sql)

    def commit(self):
        self.conn.commit()

    def __execute(self, sql):
        self.cur.execute(sql)

    def close(self):
        self.cur.close()
        self.conn.close()

def get_day(file_path):
    """
    自分の環境に合わせて適当に変更
    """
    return splitext(basename(file_path))[0].split("_")[1].replace("-", "")

def main(pcap_dir):
    table_list = []
    db = DB()
    for file_path in sorted(glob(pcap_dir+"/*")):
        print "processing ->", file_path
        day = get_day(file_path)
        if day not in table_list:
            db.create_table(day)
            table_list.append(day)
        for row in pcap2csv(file_path):
            db.insert(day, row)
        db.commit()
    db.close()

if __name__ == '__main__':
    main("pcapがあるディレクトリ名")



3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2