DIY-pcap 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,6 +34,10 @@ module DIY
34
34
  @timeout = timeout
35
35
  end
36
36
 
37
+ def error_on_stop(*)
38
+ @error_on_stop = true
39
+ end
40
+
37
41
  def client(ip_or_iport)
38
42
  @curi = ip_or_iport_with_default(ip_or_iport, 7878)
39
43
  end
@@ -78,6 +82,9 @@ module DIY
78
82
  if @filter
79
83
  @client.filter(@filter)
80
84
  @server.filter(@filter)
85
+ else
86
+ @client.filter("")
87
+ @server.filter("")
81
88
  end
82
89
  end
83
90
 
@@ -90,6 +97,7 @@ module DIY
90
97
  controller = Controller.new( @client, @server, @offline, @strategy_builder )
91
98
  controller.before_send(&@before_send_hook)
92
99
  controller.timeout(@timeout) if @timeout
100
+ controller.error_on_stop if @error_on_stop
93
101
  controller.run
94
102
  end
95
103
 
@@ -10,9 +10,11 @@ module DIY
10
10
  @strategy = strategy
11
11
  @before_send = nil
12
12
  @timeout = nil
13
+ @error_on_stop = nil
13
14
  end
14
15
 
15
16
  def run
17
+ do_trap
16
18
  client = @client
17
19
  server = @server
18
20
 
@@ -24,25 +26,40 @@ module DIY
24
26
 
25
27
  loop do
26
28
  begin
27
- pkts = @offline.nexts
29
+ pkts, where = @offline.nexts
30
+ case where
31
+ when :A
32
+ client, server = @client, @server
33
+ when :B
34
+ client, server = @server, @client
35
+ end
28
36
  one_round( client, server, pkts )
29
- client, server = server, client
30
37
  rescue HopePacketTimeoutError, UserError, FFI::PCap::LibError => e
31
38
  DIY::Logger.warn( "Timeout: Hope packet is #{pkts[0].pretty_print} ") if e.kind_of?(HopePacketTimeoutError)
32
39
  @fail_count += 1
33
- begin
34
- @offline.next_pcap
35
- server.terminal
36
- rescue EOFError
40
+ if @error_on_stop and e.kind_of?(HopePacketTimeoutError)
37
41
  client.terminal
38
42
  server.terminal
43
+ DIY::Logger.info "Error_on_stop flag opened, stopping..."
44
+ DIY::Logger.info "Dump mac learn table(size is #{@offline.mac_learner.size})... "
45
+ DIY::Logger.info @offline.mac_learner.dump
39
46
  break
40
47
  end
41
- client,server = @client, @server
48
+ #~ begin
49
+ #~ @offline.next_pcap
50
+ #~ server.terminal
51
+ #~ rescue EOFError
52
+ #~ client.terminal
53
+ #~ server.terminal
54
+ #~ break
55
+ #~ end
56
+ #~ client,server = @client, @server
42
57
  rescue EOFError
43
58
  client.terminal
44
59
  server.terminal
45
60
  break
61
+ ensure
62
+ #~ client, server = server, client
46
63
  end
47
64
  end
48
65
  DRb.stop_service
@@ -50,6 +67,19 @@ module DIY
50
67
  stats_result( end_time - start_time, @fail_count )
51
68
  end
52
69
 
70
+ def do_trap
71
+ Signal.trap("INT") do
72
+ DIY::Logger.info "bye.."
73
+ stop
74
+ exit 0
75
+ end
76
+ end
77
+
78
+ def stop
79
+ @client.terminal
80
+ @server.terminal
81
+ end
82
+
53
83
  def one_round( client, server, pkts )
54
84
  @error_flag = nil
55
85
  @round_count = 0 unless @round_count
@@ -58,22 +88,32 @@ module DIY
58
88
  if pkts.size >= 10
59
89
  DIY::Logger.info "queue size too big: #{pkts.size}, maybe something error"
60
90
  end
61
- server.ready do |recv_pkt|
62
- next if @error_flag # error accur waiting other thread do with it
63
- recv_pkt = Packet.new(recv_pkt)
91
+
92
+ recv_pkt_proc_set( pkts )
93
+ server.ready(&@recv_pkt_proc)
94
+
95
+ client_send(client, pkts)
96
+ wait_recv_ok(pkts)
97
+ server.terminal
98
+ end
99
+
100
+ # 设置回调入口, 由 worker 通过DRb 远程调用
101
+ def recv_pkt_proc_set(queue)
102
+ @queue_keeper = queue
103
+ # 不重新赋值, 防止 DRb 回收
104
+ @recv_pkt_proc ||= lambda do |recv_pkt|
64
105
  begin
65
- @strategy.call(pkts.first, recv_pkt, pkts)
106
+ next if @error_flag # error accur waiting other thread do with it
107
+ @recv_pkt_keeper = Packet.new(recv_pkt)
108
+ @strategy.call(@queue_keeper.first, @recv_pkt_keeper, @queue_keeper)
66
109
  rescue DIY::UserError =>e
67
110
  DIY::Logger.warn("UserError Catch: " + e.inspect)
68
111
  e.backtrace.each do |msg|
69
112
  DIY::Logger.info(msg)
70
113
  end
71
114
  @error_flag = e
72
- end
115
+ end
73
116
  end
74
- client_send(client, pkts)
75
- wait_recv_ok(pkts)
76
- server.terminal
77
117
  end
78
118
 
79
119
  def client_send(client, pkts)
@@ -108,9 +148,13 @@ module DIY
108
148
  @timeout = timeout
109
149
  end
110
150
 
151
+ def error_on_stop(*)
152
+ @error_on_stop = true
153
+ end
154
+
111
155
  def stats_result( cost_time, fail_count )
112
- DIY::Logger.info " ====== Finished in #{cost_time} seconds"
113
- DIY::Logger.info " ====== #{offline_result}, #{fail_count} failures"
156
+ DIY::Logger.info " Finished in #{cost_time} seconds"
157
+ DIY::Logger.info " #{offline_result}, #{fail_count} failures"
114
158
  end
115
159
 
116
160
  def offline_result
@@ -9,6 +9,10 @@ module DIY
9
9
  # 没有报文被指定时
10
10
  class ZeroOfflineError < Error; end
11
11
 
12
+ # 报文分解失败
13
+ class MacLearnConflictError < Error; end
14
+ class PacketInvalidError < Error; end
15
+
12
16
  class UserError < Error
13
17
  def initialize(real_exception)
14
18
  @real_exception = real_exception
@@ -6,7 +6,7 @@ module DIY
6
6
  class Live
7
7
  def initialize(device_name)
8
8
  DIY::Logger.info( "Initialize Live: #{device_name}" )
9
- @live = FFI::PCap::Live.new(:dev=>device_name, :handler => FFI::PCap::CopyHandler, :promisc => true)
9
+ @live = FFI::PCap::Live.new(:dev=>device_name, :handler => FFI::PCap::CopyHandler, :promisc => true, :timeout=>1)
10
10
  DIY::Logger.info( "Listen on: #{net} " )
11
11
  @running = false
12
12
  @live.non_blocking= true
@@ -1,5 +1,8 @@
1
1
  module DIY
2
2
  class MacLearner
3
+ BROAD_MAC = "\377" * 6 # ff:ff:ff:ff:ff:ff
4
+ GROUP_MAC = 1
5
+ LEARN_TIME = 60 * 5 # five minutes
3
6
  def initialize(default_host = :A)
4
7
  @default_host = default_host
5
8
  @table = {}
@@ -13,20 +16,71 @@ module DIY
13
16
  end
14
17
 
15
18
  def _learn(mac, where)
16
- @table[mac] = where
19
+ # 除去组播与广播
20
+ return if mac == BROAD_MAC
21
+ return if mac[0] & GROUP_MAC == 1
22
+ set(mac, where)
23
+ end
24
+
25
+ def get(mac)
26
+ @table[mac] && @table[mac][0]
27
+ end
28
+
29
+ def get_time(mac)
30
+ @table[mac] && @table[mac][1]
31
+ end
32
+
33
+ def set(mac, where)
34
+ time_now = Time.now
35
+ if @table[mac]
36
+ if @table[mac][0] != where
37
+ if (time_now - @table[mac][1]) <= LEARN_TIME
38
+ raise DIY::MacLearnConflictError, "Found mac learn port confict when set #{Utils.pp_mac(mac)} to #{where}"
39
+ end
40
+ end
41
+ end
42
+ @table[mac] = [ where, time_now ]
43
+ end
44
+
45
+ def clear(mac)
46
+ @table[mac] = nil
17
47
  end
18
48
 
19
49
  # 报告包所在的端口 A or B
20
50
  # 如果包不在学习表内, 返回缺省端口(默认为A)
21
51
  def tellme(packet)
52
+ valid!(packet)
22
53
  src_p = src(packet)
23
- if @table.has_key? src_p
24
- where = @table[src_p]
54
+ dst_p = dst(packet)
55
+
56
+ if src_p == dst_p
57
+ DIY::Logger.debug("Found SRC mac is the same with DST mac: #{Utils.pp(packet)}")
58
+ #~ where = @default_host
59
+ #~ _learn(src_p, where)
60
+ #~ return where
61
+ end
62
+
63
+ if src_p != dst_p && get(src_p) && get(src_p) == get(dst_p)
64
+ #~ if (get_time(src_p) - get_time(dst_p)).abs <= LEARN_TIME
65
+ #~ DIY::Logger.warn "Found the same mac learner: packet is #{Utils.pp(packet)}"
66
+ raise DIY::MacLearnConflictError, "Found mac learn port confict"
67
+ #~ else
68
+ #~ cls = get_time(src_p) > get_time(dst_p) ? dst_p : src_p
69
+ #~ clear(cls)
70
+ #~ end
71
+ end
72
+
73
+ if get(src_p)
74
+ where = get(src_p)
75
+ _learn( src_p, where )
76
+ elsif get(dst_p)
77
+ where = other( get(dst_p) )
78
+ _learn( src_p, where )
25
79
  else
26
80
  where = @default_host
27
- _learn( src(packet), where )
81
+ _learn( src_p, where )
28
82
  end
29
- _learn( dst(packet), other(where) )
83
+ _learn( dst_p, other(where) )
30
84
  where
31
85
  end
32
86
 
@@ -40,6 +94,20 @@ module DIY
40
94
  end
41
95
  end
42
96
 
97
+ def size
98
+ @table.size
99
+ end
100
+
101
+ def dump
102
+ ret = "begin dumpping...\n"
103
+ @table.each do |k, v|
104
+ mac = Utils.pp_mac(k)
105
+ ret += "#{mac} -> "
106
+ ret += "#{v[0]}, "
107
+ ret += "created at: #{ v[1].strftime("%H:%M:%S") }\n"
108
+ end
109
+ ret += "end dump...\n"
110
+ end
43
111
 
44
112
  private
45
113
  def src(packet)
@@ -49,5 +117,9 @@ module DIY
49
117
  def dst(packet)
50
118
  Utils.dst_mac(packet)
51
119
  end
120
+
121
+ def valid!(packet)
122
+ raise DIY::PacketInvalidError, "packet too small" unless packet.size >= 12
123
+ end
52
124
  end
53
125
  end
@@ -6,6 +6,7 @@ module DIY
6
6
  def initialize( pcap_files )
7
7
  @pcap_files = [ pcap_files ] if pcap_files.kind_of?(String)
8
8
  @pcap_files ||= pcap_files
9
+ raise ZeroOfflineError, "no files found" if @pcap_files.size == 0
9
10
  @off = FFI::PCap::Offline.new(@pcap_files[0])
10
11
 
11
12
  @ml = MacLearner.new
@@ -14,11 +15,27 @@ module DIY
14
15
  @position = 0
15
16
  # 记录包在当前文件的位置
16
17
  @num = 0
18
+ # 记录所有包的个数
19
+ @total = 0
17
20
 
18
21
  @tmp_pcap = nil
19
22
  end
20
23
 
24
+ def mac_learner
25
+ @ml
26
+ end
27
+
21
28
  def nexts
29
+ begin
30
+ return _nexts
31
+ rescue DIY::MacLearnConflictError, DIY::PacketInvalidError =>e
32
+ DIY::Logger.warn "Found Error when parse #{fullname}: #{e.message}"
33
+ next_pcap
34
+ retry
35
+ end
36
+ end
37
+
38
+ def _nexts
22
39
  ret = []
23
40
  # 取一个
24
41
  pkt = fetch_one
@@ -32,10 +49,14 @@ module DIY
32
49
 
33
50
  loop do
34
51
  pkt = fetch_one
35
- return ret if pkt.nil?
52
+ return [ret, where] if pkt.nil?
53
+ #~ if pkt.nil?
54
+ #~ next_pcap
55
+ #~ pkt = fetch_one
56
+ #~ end
36
57
  if @ml.tellme(pkt.content) != where
37
58
  cached(pkt)
38
- return ret
59
+ return [ret, where]
39
60
  else
40
61
  ret << pkt
41
62
  end
@@ -55,6 +76,7 @@ module DIY
55
76
  def next
56
77
  pkt = @off.next
57
78
  @num += 1
79
+ @total += 1
58
80
  return nil if pkt.nil?
59
81
 
60
82
  return Packet.new(pkt.copy.body, fullname)
@@ -100,7 +122,7 @@ module DIY
100
122
  end
101
123
 
102
124
  def now_size
103
- @num
125
+ @total
104
126
  end
105
127
 
106
128
  def files_size
@@ -81,7 +81,8 @@ class IPv4 < IP
81
81
  when IPPROTO_UDP
82
82
  ipv4.payload = UDP.from_bytes payload
83
83
  when IPPROTO_SCTP
84
- ipv4.payload = SCTP.from_bytes payload
84
+ #ipv4.payload = SCTP.from_bytes payload
85
+ ipv4.payload = payload
85
86
  else
86
87
  ipv4.payload = payload
87
88
  end
@@ -34,7 +34,7 @@ module DIY
34
34
  raise StrategyCallError.new(e)
35
35
  else
36
36
  if ret == Strategy::OK
37
- logger.info("pkt same:")
37
+ logger.info("pkt same: #{hope_pkt.pretty_print}")
38
38
  queue.shift
39
39
  return
40
40
  elsif ret == Strategy::OK_NO_POP
@@ -16,7 +16,7 @@ module DIY
16
16
  begin
17
17
  new_pkt = pkt.dup
18
18
  Mu::Pcap::Ethernet.from_bytes(new_pkt).to_s + size_print_str
19
- rescue Mu::Pcap::ParseError =>e
19
+ rescue Mu::Pcap::ParseError, Exception =>e
20
20
  DIY::Logger.debug "parse error from pkt: " + ( pkt[0..10] + "..." ).dump + size_print_str
21
21
  return ( pkt[0..10] + "..." ).dump + size_print_str + "( parse failed )"
22
22
  end
@@ -32,6 +32,15 @@ module DIY
32
32
  pkt[0..5]
33
33
  end
34
34
 
35
+ def pp_mac(mac)
36
+ raise "MAC MUST BE 6 sizes" unless mac.size == 6
37
+ begin
38
+ '%02x:%02x:%02x:%02x:%02x:%02x' % mac.unpack('C6')
39
+ rescue ArgumentError
40
+ mac.dump
41
+ end
42
+ end
43
+
35
44
  def wait_until( timeout = 20, &block )
36
45
  timeout(timeout) do
37
46
  loop do
@@ -54,6 +63,14 @@ module DIY
54
63
  new_bt
55
64
  end
56
65
 
66
+ def print_backtrace(e)
67
+ DIY::Logger.info "Dump Exception: #{e.class} -> #{e.message}..."
68
+ e.backtrace.each do |msg|
69
+ DIY::Logger.info(msg)
70
+ end
71
+ DIY::Logger.info("Dump end!")
72
+ end
73
+
57
74
  def ary_match(ary, msg)
58
75
  ary.each do |e|
59
76
  return true if /#{Regexp.escape(e)}/ === msg
@@ -1,5 +1,5 @@
1
1
  module DIY
2
2
  class PCAP
3
- VERSION = "0.3.5"
3
+ VERSION = "0.3.6"
4
4
  end
5
5
  end
@@ -45,10 +45,14 @@ module DIY
45
45
  begin
46
46
  pkt = @queue.pop
47
47
  #~ DIY::Logger.info "callback: #{pkt}"
48
- @block.call(pkt) if @block
48
+ @block.call(pkt) if @start and @block
49
49
  rescue DRb::DRbConnError
50
50
  DIY::Logger.info "closed connection by controller"
51
+ @start = false
51
52
  @queue.clear
53
+ rescue RangeError=>e
54
+ DIY::Utils.print_backtrace(e)
55
+ raise e
52
56
  end
53
57
  end
54
58
  DIY::Logger.debug "stopped loop callback"
@@ -57,6 +61,7 @@ module DIY
57
61
 
58
62
  #收包
59
63
  def ready(&block)
64
+ @start = false
60
65
  DIY::Logger.info("start recv pkt")
61
66
  @block = block
62
67
  @queue.clear
@@ -131,4 +131,15 @@ describe "Controller" do
131
131
  lambda { build2.run }.should_not raise_error
132
132
  end
133
133
 
134
+ it "#run with error_on_stop" do
135
+ build2 = DIY::Builder.new do
136
+ use DIY::SimpleStrategy.new
137
+ filter "not tcp"
138
+ error_on_stop
139
+ pcapfiles ["helper/http.pcap", "helper/gre.pcap"]
140
+ timeout 1
141
+ end
142
+ lambda { build2.run }.should_not raise_error
143
+ end
144
+
134
145
  end
Binary file
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ describe DIY::MacLearner do
3
+
4
+ before(:each) do
5
+ @ml = DIY::MacLearner.new
6
+ end
7
+
8
+ def make_packet(src, dst)
9
+ src = src * 6
10
+ dst = dst * 6
11
+ dst + src
12
+ end
13
+
14
+ it "#tellme new packet" do
15
+ pkt = make_packet( "\2", "\4")
16
+ @ml.tellme(pkt).should == :A
17
+ end
18
+
19
+ it "#tellme again packet" do
20
+ pkt = make_packet( "\2", "\4" )
21
+ @ml.tellme(pkt)
22
+ @ml.tellme(pkt).should == :A
23
+ #~ @ml.instance_variable_get("@table").size.should == 1
24
+ b_pkt = make_packet( "\4" , "\2" )
25
+ @ml.tellme(b_pkt).should == :B
26
+ #~ @ml.instance_variable_get("@table").size.should == 2
27
+ # 另一个新包
28
+ c_pkt = make_packet( "\6", "\8" )
29
+ @ml.tellme(c_pkt).should == :A
30
+ #~ @ml.instance_variable_get("@table").size.should == 3
31
+ #~ pp @ml.instance_variable_get("@table")
32
+ # 目标地址选定的
33
+ d_pkt = make_packet( "\8", "\2")
34
+ @ml.tellme(d_pkt).should == :B
35
+ #~ pp @ml.instance_variable_get("@table")
36
+ @ml.instance_variable_get("@table")["\8"*6][0].should == :B
37
+ dd_pkt = make_packet( "\8", "\10")
38
+ @ml.tellme(dd_pkt).should == :B
39
+ # 有冲突的
40
+ e_pkt = make_packet( "\2", "\6" )
41
+ lambda { @ml.tellme(e_pkt) }.should raise_error(DIY::MacLearnConflictError)
42
+ # 解决冲突
43
+ #~ @ml.instance_variable_get("@table")[ "\6"*6 ][1] = Time.now - 10*60
44
+ #~ @ml.tellme(e_pkt).should == :A
45
+ #~ @ml.tellme(e_pkt).should == :A
46
+
47
+ # 源目的相同的
48
+ ee_pkt = make_packet( "\2", "\2")
49
+ lambda { @ml.tellme(ee_pkt) }.should raise_error(DIY::MacLearnConflictError)
50
+ end
51
+
52
+ it "#tellme group and broad" do
53
+ @ml.tellme( make_packet("\2", "\377") ).should == :A
54
+ @ml.tellme( make_packet( "\377", "\2") ).should == :B
55
+ @ml.instance_variable_get("@table").size.should == 1
56
+ @ml.tellme( make_packet("\377", "\4") ).should == :A
57
+
58
+ @ml.tellme( make_packet("\1", "\4")).should == :A
59
+ @ml.tellme( make_packet("\6", "\1")).should == :A
60
+ @ml.tellme( make_packet("\4", "\1")).should == :B
61
+ end
62
+ end
@@ -9,35 +9,41 @@ describe DIY::Offline do
9
9
  lambda { offline.next_pcap }.should raise_error(DIY::EOFError)
10
10
  end
11
11
 
12
+ it "no file" do
13
+ lambda { DIY::Offline.new([]) }.should raise_error(DIY::ZeroOfflineError)
14
+ end
15
+
12
16
  it "should get next special first_pkt" do
13
17
  files = [ "helper/app.pcap", "helper/gre.pcap" ]
14
18
  offline = DIY::Offline.new(files)
15
19
  22.times { offline.nexts }
16
- offline.nexts.size.should == 1
20
+ offline.nexts[0].size.should == 1
17
21
  end
18
22
 
19
23
  it "should get nexts two" do
20
24
  files = [ "helper/gre.pcap", "helper/app.pcap" ]
21
25
  offline = DIY::Offline.new(files)
22
- offline.nexts.size.should == 1
23
- offline.nexts.size.should == 2
24
- offline.nexts.size.should == 2
26
+ offline.nexts[0].size.should == 1
27
+ offline.nexts[0].size.should == 2
28
+ offline.nexts[0].size.should == 2
25
29
  offline.next_pcap
26
- offline.nexts.size.should == 1
27
- offline.nexts.size.should == 7
30
+ offline.nexts[0].size.should == 1
31
+ offline.nexts[0].size.should == 7
28
32
  lambda { loop do offline.nexts end }.should raise_error(DIY::EOFError)
29
33
  end
30
34
 
31
35
  it "should get another two" do
32
36
  files = [ "helper/http.pcap", "helper/gre.pcap" ]
33
37
  offline = DIY::Offline.new(files)
34
- offline.nexts.size.should == 1
35
- offline.nexts.size.should == 1
36
- offline.nexts.size.should == 1
38
+ offline.nexts[0].size.should == 1
39
+ offline.nexts[0].size.should == 1
40
+ offline.nexts[0].size.should == 1
37
41
  #change to next
38
- offline.nexts.size.should == 1
39
- offline.nexts.size.should == 2
40
- offline.nexts.size.should == 2
42
+ a = offline.nexts
43
+ a[0].size.should == 1
44
+ a[1].should == :A
45
+ offline.nexts[0].size.should == 2
46
+ offline.nexts[0].size.should == 2
41
47
  lambda { loop do offline.nexts end }.should raise_error(DIY::EOFError)
42
48
  end
43
49
 
@@ -46,7 +52,7 @@ describe DIY::Offline do
46
52
  600.times do
47
53
  files << "helper/http.pcap"
48
54
  end
49
- puts "files size = #{files.size}"
55
+ #~ puts "files size = #{files.size}"
50
56
  offline = DIY::Offline.new(files)
51
57
  lambda {
52
58
  loop do
@@ -5,6 +5,11 @@ describe DIY::Utils do
5
5
  DIY::Utils.pp('a' * 100).should match(/\(100 sizes\)/)
6
6
  end
7
7
 
8
+ it "#pp parse error" do
9
+ badtcp = File.open('helper/badtcp.dat', 'rb') { |io| io.read }
10
+ lambda { puts DIY::Utils.pp(badtcp) }.should_not raise_error
11
+ end
12
+
8
13
  it "#pp false" do
9
14
  DIY::Utils.pp('a' * 100, false).should_not match(/\(100 sizes\)/)
10
15
  end
@@ -16,5 +21,17 @@ describe DIY::Utils do
16
21
  it "#dst_mac" do
17
22
  DIY::Utils.dst_mac( 'a' * 100 ).should == "a" * 6
18
23
  end
24
+
25
+ it "#pp_mac" do
26
+ DIY::Utils.pp_mac( "\377" * 6 ).should == "ff:ff:ff:ff:ff:ff"
27
+ end
28
+
29
+ it "#print_backtrace" do
30
+ begin
31
+ raise
32
+ rescue
33
+ lambda { DIY::Utils.print_backtrace($!) }.should_not raise_error
34
+ end
35
+ end
19
36
 
20
37
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: DIY-pcap
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 3
9
- - 5
10
- version: 0.3.5
8
+ - 6
9
+ version: 0.3.6
11
10
  platform: ruby
12
11
  authors:
13
12
  - yafei Lee
@@ -15,7 +14,8 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2012-10-15 00:00:00 Z
17
+ date: 2012-10-22 00:00:00 +08:00
18
+ default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: ffi-pcap
@@ -25,7 +25,6 @@ dependencies:
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- hash: 23
29
28
  segments:
30
29
  - 0
31
30
  - 2
@@ -129,6 +128,7 @@ files:
129
128
  - spec/controller_spec.rb
130
129
  - spec/device_finder_spec.rb
131
130
  - spec/helper/app.pcap
131
+ - spec/helper/badtcp.dat
132
132
  - spec/helper/gre.pcap
133
133
  - spec/helper/http.pcap
134
134
  - spec/helper/long.dat
@@ -142,12 +142,14 @@ files:
142
142
  - spec/helper/vlan.dat
143
143
  - spec/live_spec.rb
144
144
  - spec/logger_spec.rb
145
+ - spec/mac_learner_spec.rb
145
146
  - spec/mu_parser_spec.rb
146
147
  - spec/offline_spec.rb
147
148
  - spec/packet_spec.rb
148
149
  - spec/spec_helper.rb
149
150
  - spec/utils_spec.rb
150
151
  - spec/worker_spec.rb
152
+ has_rdoc: true
151
153
  homepage: ""
152
154
  licenses: []
153
155
 
@@ -161,7 +163,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
163
  requirements:
162
164
  - - ">="
163
165
  - !ruby/object:Gem::Version
164
- hash: 3
165
166
  segments:
166
167
  - 0
167
168
  version: "0"
@@ -170,14 +171,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
171
  requirements:
171
172
  - - ">="
172
173
  - !ruby/object:Gem::Version
173
- hash: 3
174
174
  segments:
175
175
  - 0
176
176
  version: "0"
177
177
  requirements: []
178
178
 
179
179
  rubyforge_project:
180
- rubygems_version: 1.8.24
180
+ rubygems_version: 1.3.7
181
181
  signing_key:
182
182
  specification_version: 3
183
183
  summary: DIY pcap send and recv