DIY-pcap 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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