RubyでTCP/IPパケットキャプチャ

プログラミング言語Rubyは,プログラムを書いていて気持ちが良い,実にハッカー向きの言語だと思います.
なので,ハッカーが色々なライブラリを開発し続けてくれて,どんどん便利になっています.

一例として,今や生活に欠かせないインターネットの,通信内容を調べるプログラムを書きたくなった場合に便利なライブラリの一つにパケットキャプチャライブラリ「Pcap」があります.
http://www.goto.info.waseda.ac.jp/~fukusima/ruby/pcap-j.html

Ruby/Pcap 拡張ライブラリ

Ruby から LBL の Packet Capture Library を使うための拡張ライブラリです。TCP/IPのヘッダの情報にアクセスするためのクラスも含んでいます。

C 言語から直接 pcap を使うよりはずっと楽にプログラムが書けます。例えば tcpdump もどきのプログラムはこれだけで書けます。

tcpdumpTCPプロトコルで通信されている内容の解析に使われます.
私は,tcpdumpよりも上位レイヤー的で使い易いtcpflowをよく使います.
tcpflow -- TCP Flow Recorder

What is tcpflow?

tcpflow is a program that captures data transmitted as part of TCP connections (flows), and stores the data in a way that is convenient for protocol analysis or debugging. A program like 'tcpdump' shows a summary of packets seen on the wire, but usually doesn't store the data that's actually being transmitted. In contrast, tcpflow reconstructs the actual data streams and stores each flow in a separate file for later analysis.
(適当な抄訳)
tcpdumpTCPプロトコルの細かい振る舞いを記録してくれるが,実際に流れている通信内容を記録してくれない.tcpflowは,ネットワーク上を流れるTCPのデータ内容を記録する.

話は戻りましてPcapですが,「例えば tcpdump もどきのプログラムはこれだけで書けます。」とリンクが張られております.その内容は,次のようなものです.

#!/usr/local/bin/ruby
require 'pcaplet'
include Pcap

class Time
  # tcpdump style format
  def to_s
    sprintf "%0.2d:%0.2d:%0.2d.%0.6d", hour, min, sec, tv_usec
  end
end

pcaplet = Pcaplet.new
pcaplet.each_packet { |pkt|
  print "#{pkt.time} #{pkt}"
  if pkt.tcp?
    print " (#{pkt.tcp_data_len})"
    print " ack #{pkt.tcp_ack}" if pkt.tcp_ack?
    print " win #{pkt.tcp_win}"
  end
  if pkt.ip?
    print " (DF)" if pkt.ip_df?
  end
  print "\n"
}
pcaplet.close

僅か25行です.Rubyの強力さが分かるというものです.
例えば,Webサーバをポート80で運営しており,その内容を監視したいとしましょう.すると,次のようなプログラムで通信内容を見ることができます.

#!/usr/bin/ruby
require 'pcap'
def capture_data(interval)
  capdat = [];
  i = 0;
  pcaplet = Pcap::Capture.open_live("eth0", 1460,true,1000);
  access = Pcap::Filter.new('tcp and dst port 80',pcaplet);
  pcaplet.setfilter(access);
  pcaplet.each_packet { |pkt|
    if pkt.tcp_data_len>0 then
      p pkt.tcp_data;
      i += 1;
    end;
    break if i>interval;
  }
  pcaplet.close
end;

capture_data(10);

プログラム中の「eth0」は,ifconfigで出るネットワークカード名に変更して下さい.
このプログラムを実行すると,Webサーバにアクセスが来ると,次のように表示されます.

"GET /index.html HTTP/1.1\r\nAccept: */*\r\nAccept-Language: ja\r\nAccept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)\r\nHost: www.example.jp\r\nConnection: Keep-Alive\r\n\r\n"

TCPプロトコル上で,HTTPプロトコルの通信が来ていることが分かります.
便利なものです.
このサンプルは10パケット受信すると止まってしまいます.パケット数を増減させるには,capture_data(10)の「10」の値を変えて下さい.