LoginSignup
14
14

More than 5 years have passed since last update.

PacketFuでのパケットキャプチャ

Last updated at Posted at 2015-03-05

rubyでパケットキャプチャツールってないのかなの思ったらQiitaの記事:PacketFuでARPリクエストのモニタリングでPacketFuを見つけたので試しに動かしてみた。

環境

  • OS: Mac X 10.9.3
  • Ruby: 2.2.1
  • packetfu: 1.1.10
  • pcaprub: 0.12.0

インストール

gemでインストール。

$ gem install packetfu pcaprub

とりあえず動かす

Qiitaの記事:PacketFuでARPリクエストのモニタリングを見る限り、ディスプレイフィルタリングを利用できるらしい。

まずは本当にキャプチャできるのかを試すために以下のサンプルスクリプトを作成してみた。

capure.rb
#!/usr/bin/env ruby

require "packetfu"
include PacketFu

def get_capture(iface,filter)
  cap = Capture.new(:iface=>iface, :start=>true,
                  :filter=>filter)
  cap.stream.each do |pkt|
    puts pkt
  end
end

if $0 == __FILE__
  iface = ARGV[0]
  filter = ARGV[1]
  get_capture(iface, filter)
end

以下実行結果。
root権限がないとキャプチャはできないのでご注意を。
バイナリで何かを取得しているのがわかる。

$ sudo ruby capture.rb en0 tcp
<??^*>????E(?a-_⢟?Ӭ
??? ???U٪1P?#
>????d<??^E(?@@?l?
???????U٪1 ??@P@?J
R??^*>????Ea??K??
??W?Y??pOj???
^Ccapture.rb:9:in `each': Interrupt
    from capture.rb:9:in `get_capture'
    from capture.rb:19:in `<main>'
$

TCPパケットのパース

さてパケットをキャプチャをしているっぽいので次はTCPパケットをパースしてやる。

PacketFuのソースを見ると、L7以下の各種プロトコルのヘッダーは用意されていそう。

以下に時刻、SrcMac, DstMac, SrcIP, SrcPort, DestIP, DestPortを取得するスクリプトを作成した。

capure.rb
#!/usr/bin/env ruby

require "packetfu"
include PacketFu

def get_capture(iface,filter)
  cap = Capture.new(:iface=>iface, :start=>true,
                  :filter=>filter)
  cap.stream.each do |pkt|
    next unless TCPPacket.can_parse?(pkt)
    t_stamp  = Time.now.strftime("%Y-%m-%d %H:%M:%S.%6N")
    tcp_packet = TCPPacket.parse(pkt)
    src_mac = EthHeader.str2mac(tcp_packet.eth_src)
    dst_mac = EthHeader.str2mac(tcp_packet.eth_dst)
    src_ip = IPHeader.octet_array(tcp_packet.ip_src).join('.')
    dst_ip = IPHeader.octet_array(tcp_packet.ip_dst).join('.')
    src_port = tcp_packet.tcp_src
    dst_port = tcp_packet.tcp_dst
    puts "time:#{t_stamp},src_mac:#{src_mac},dst_mac:#{dst_mac},src_ip:#{src_ip},dst_ip:#{dst_ip},src_port:#{src_port},dst_port:#{dst_port}"
  end

end


if $0 == __FILE__
  iface = ARGV[0]
  filter = ARGV[1]
  get_capture(iface, filter)
end

簡単に説明すると、next unless TCPPacket.can_parse?(pkt)でTCPパケット以外は読み飛ばして、TCPPacket.parse(pkt)でTCPパケットをパースしL2->L4までの構造体にいい感じに値を格納してくれているみたい。
その後は見やすいように変換処理をしているだけ。

実行すると以下のように表示される。

$ sudo ruby capture.rb en0 tcp
time:2015-03-05 01:24:07.268786,src_mac:xx:xx:c2:d3:5e:2a,dst_mac:xx:xx:8e:98:df:64,src_ip:172.20.10.5,dst_ip:118.151.171.74,src_port:50338,dst_port:80

これは結構便利そう。

14
14
1

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
14
14