2011/05/27

libpcap-rubyを使ってパケットキャプチャ

Hokkaido.cap(パケットキャプチャ勉強会)の主催(とはいえ僕の担当は司会)をやってることもあって、ちょっとRubyを使ってパケットキャプチャしてみようと思いました。Debianにはlibpcap-rubyというパッケージがあるので、それをaptitude installするだけです。

参考:Ruby/Pcap拡張ライブラリ

ソースは以下。


#!/usr/bin/ruby

require 'pcap'

def cap_data(dev,filstr,count)
  # [device],[snaplen],[promisc?],[read timeout(ms)]
  pcaplet = Pcap::Capture.open_live(dev,1460,true,1000)

  access = Pcap::Filter.new(filstr,pcaplet)
  pcaplet.setfilter(access)
  pcaplet.each_packet(count) do |pkt|
    odata = String.new
    if pkt.tcp? == true then
       odata = "[TCP]"
       odata = odata + pkt.ip_src.to_s + ":" + pkt.tcp_sport.to_s + " -> "
       odata = odata + pkt.ip_dst.to_s + ":" + pkt.tcp_dport.to_s + " "
       odata = odata + pkt.tcp_data.to_s
       p odata
    elsif pkt.udp? == true then
       odata = "[UDP]"
       odata = odata + pkt.ip_src.to_s + ":" + pkt.udp_sport.to_s + " -> "
       odata = odata + pkt.ip_dst.to_s + ":" + pkt.udp_dport.to_s + " "
       odata = odata + pkt.udp_data.to_s
       p odata
    elsif pkt.ip? == true then
       odata = "[IP]"
       odata = odata + pkt.ip_src.to_s + " -> "
       odata = odata + pkt.ip_dst.to_s ; " "
       odata = odata + pkt.ip_data.to_s
       p odata
    end
  end
  pcaplet.close
end

# [capture device],[filter strings],[count(負の数だと無限繰り返し)]
# SSH通信をFilter(リモート作業の関係で)
cap_data("eth0","!src port 22 and !dst port 22",-1);

exit
出力結果は以下。
"[UDP]172.16.1.1:53 -> 172.20.0.130:37717 a\264\201\200\000\001\000\003\000\000\000\000\003ftp\002jp\006debian\003org\000\000\001\000\001\300\f\000\005\000\001\000\000\vA\000\022\003cdn\006debian\002or\002jp\000\300/\000\005\000\001\000\006v]\000\022\002jp\003cdn\005araki\003net\000\300M\000\001\000\001\000\000\000<\000\004\226A\a\202"
"[TCP]172.20.0.130:54574 -> 150.65.7.130:80 "
"[TCP]172.20.0.130:54574 -> 150.65.7.130:80 GET /debian/dists/squeeze/Release.gpg HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nIf-Modified-Since: Sat, 19 Mar 2011 13:23:11 GMT\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\nGET /debian/dists/squeeze/main/i18n/Translation-en.bz2 HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\nGET /debian/dists/squeeze/main/i18n/Translation-ja.bz2 HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nIf-Modified-Since: Fri, 04 Feb 2011 12:30:31 GMT\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\nGET /debian/dists/squeeze-updates/Release.gpg HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nIf-Modified-Since: Fri, 27 May 2011 02:22:14 GMT\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\nGET /debian/dists/squeeze-updates/main/i18n/Translation-en.bz2 HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\nGET /debian/dists/squeeze-updates/main/i18n/Translation-ja.bz2 HTTP/1.1\r\nHost: ftp.jp.debian.org\r\nConnection: keep-alive\r\nUser-Agent: Debian APT-HTTP/1.3 (0.8.10.3)\r\n\r\n"
パケットヘッダを個別に取得するメソッドもあるし、データ部も可読化してやれば結構使えそう。pcapファイルをOpenして読み込むことも出来るようで、GUIであるが故に大量のデータの読み込みが遅かったりするところを、Rubyを使って必要なデータだけピックアップする、というのは便利そうかな。なかなか良い感じだと思いました。