Ruby/Pcap 拡張ライブラリを用いたパケットデータベースの実装例
TCP/IP と UDP/IP のパケットデータ(libpcap形式)をリレーショナルデータベースに格納し,集約,条件検索,CSV ファイルへのエクスポートを行う試み
【この Web ページを理解する前提となる関連事項】
前準備
- Linux のインストールが済んでいること
- Linux での Ruby のインストールが済んでいること
- Ruby/Pcap 拡張ライブラリのインストールが済んでいること.
概要
libpcap 形式ファイルの例
libpcap 形式ファイルはWireshark を使いパケットをキャプチャすることで簡単に作ることができる.
Wireshark のサイトからサンプルデータをダウンロードすることも簡単です.
ソースコード
libpcap 形式のパケットデータをパケットにインポートするプログラム (Ruby プログラム)
#!/usr/bin/env ruby -wKU require 'rubygems' require 'sqlite3' require 'pcap' # SQLite 3 のデータベースファイル名を DBFILENAME に設定してください. # Windows の場合は「\\」で区切る DBFILENAME = "/home/kaneko/pcap/examples/packetdb.sqlite3" DBDIR = File.dirname( DBFILENAME ) DBNAME = File.basename( DBFILENAME ) # データベースオープン Dir.chdir( DBDIR ) db = SQLite 3::Database.new( DBFILENAME ) # (オプション)SQL を用いた packets テーブルの削除 sql = <<SQL DROP TABLE tcppackets; SQL puts "drop table tcppackets..." # 削除したいときは、ここの「#」を外す #db.execute_batch(sql) # SQL を用いた packets テーブルの定義 # id 属性は SQLite 3の側で自動的に連番(整数)を付ける # その他の属性については Ruby/Pcap のドキュメントをみt欲しい sql = <<SQL create table tcppackets ( id INTEGER PRIMARY KEY, time REAL not null, size INTEGER not null, tcp_data_len INTEGER not null, ip_src INTEGER not null, tcp_sport INTEGER not null, ip_dst INTEGER not null, tcp_dport INTEGER not null, tcp_flags_s TEXT not null, tcp_seq INTEGER not null ); create table udppackets ( id INTEGER PRIMARY KEY, time REAL not null, size INTEGER not null, udp_len INTEGER not null, ip_src INTEGER not null, udp_sport INTEGER not null, ip_dst INTEGER not null, udp_dport INTEGER not null ); SQL puts "define table tcppackets..." db.execute_batch(sql) puts "insert values..." # libpcap を使い libpcap 形式のファイル traffic.cap を読み込む cap = Pcap::Capture.open_offline('traffic.cap') cap.setfilter("ip") cap.loop do |pkt| if pkt.ip? and pkt.tcp? db.execute( " insert into tcppackets values ( null, ?, ?, ?, ?, ?, ?, ?, ?, ? )", pkt.time.to_f, pkt.size, pkt.tcp_data_len, pkt.ip_src, pkt.tcp_sport, pkt.ip_dst, pkt.tcp_dport, pkt.tcp_flags_s, pkt.tcp_seq ) end if pkt.ip? and pkt.udp? db.execute( " insert into udppackets values ( null, ?, ?, ?, ?, ?, ?, ? )", pkt.time.to_f, pkt.size, pkt.udp_len, pkt.ip_src, pkt.udp_sport, pkt.ip_dst, pkt.udp_dport ) end end cap.close # 問い合わせ(確認表示) sql = <<SQL SELECT * FROM tcppackets; SQL puts "query" db.execute(sql) do |row| p row end # 問い合わせ(確認表示) sql = <<SQL SELECT * FROM udppackets; SQL puts "query" db.execute(sql) do |row| p row end
【実行手順】
- ソースコード中の次の2箇所を確認し,適切に書き換える
- 入力である libpcap 形式パケットデータファイルのファイル名: traffic.cap
- SQLite 3 データベースファイル名: /home/kaneko/pcap/examples/packetdb.sqlite3
- ソースコードを適切なファイル名で保存し,ruby 処理系を使って実行
ruby <ソースコードのファイル名>
- テーブルの中身が表示される(エラーメッセージが出ない)ことを確認
- データベースファイルが出来ていることを確認
パケットの集約の例 (SQL プログラム)
■ Source IP Address による集約の例
SELECT count(*), ip_src FROM tcppackets group by ip_src ODRER BY count(*)
【実行結果の例】
SQLite 3 コマンドラインシェル を使うのが簡単です.
SQLite 3 コマンドラインシェルでは,起動時に「sqlite packetsdb.sqlite3」のようにデータベースファイル名を指定することを忘れない.
■ Source IP Address と Source TCP Portによる集約
SELECT count(*), ip_src, tcp_sport FROM tcppackets group by ip_src, tcp_sport ODRER BY count(*)
【実行結果の例】
パケットの条件検索の例 (SQL プログラム)
SELECT * FROM tcppackets WHERE tcp_sport=3813
【実行結果の例】
CSV ファイルへのエクスポート
SQLite 3 コマンドラインシェル を使うことで, CSV ファイルへのエクスポートが簡単にできる.
SQLite 3 コマンドラインシェルを起動し,次のコマンドを実行する
.mode csv .output tcppackets.csv SELECT * FROM tcppackets; .output stdout .exit