DIY-pcap 0.0.4 → 0.2.0
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.
- data/bin/pcap +62 -5
- data/bin/rpcap +62 -6
- data/lib/diy/builder.rb +14 -16
- data/lib/diy/controller.rb +50 -33
- data/lib/diy/device_finder.rb +26 -0
- data/lib/diy/dig.rb +7 -6
- data/lib/diy/logger.rb +7 -0
- data/lib/diy/offline.rb +98 -28
- data/lib/diy/packet.rb +17 -0
- data/lib/diy/pcap.rb +40 -17
- data/lib/diy/strategy_builder.rb +5 -12
- data/lib/diy/utils.rb +12 -0
- data/lib/diy/version.rb +5 -5
- data/lib/diy/worker.rb +49 -0
- data/lib/diy/worker_keeper.rb +25 -0
- data/simple/4000port.rb +20 -0
- data/simple/4000port/r1.dat +0 -0
- data/simple/4000port/r3.dat +0 -0
- data/simple/4000port/r4.dat +0 -0
- data/simple/4000port/r6.dat +0 -0
- data/simple/4000port/r7.dat +0 -0
- data/simple/4000port/s1.dat +0 -0
- data/simple/4000port/s2.dat +0 -0
- data/simple/4000port/s3.dat +0 -0
- data/simple/4000port/s4.dat +0 -0
- data/simple/4000port/s5.dat +0 -0
- data/simple/4000port/s6.dat +0 -0
- data/simple/4000port/s8.dat +0 -0
- data/simple/howto.vsd +0 -0
- data/spec/controller_spec.rb +36 -0
- data/spec/device_finder_spec.rb +16 -0
- data/spec/offline_spec.rb +26 -29
- data/spec/worker_spec.rb +58 -0
- metadata +24 -9
- data/lib/diy/queue.rb +0 -174
- data/lib/diy/recver.rb +0 -33
- data/lib/diy/sender.rb +0 -26
- data/spec/builder_spec.rb +0 -82
- data/spec/queue_spec.rb +0 -84
- data/spec/sender_spec.rb +0 -21
data/bin/pcap
CHANGED
@@ -1,10 +1,67 @@
|
|
1
1
|
$LOAD_PATH.unshift File.join( File.dirname(__FILE__), '..', 'lib' )
|
2
|
+
require 'rubygems'
|
2
3
|
require 'diy-pcap'
|
3
4
|
require 'diy/task'
|
4
5
|
|
5
|
-
|
6
|
-
puts "Usage: #{File.basename(__FILE__)} file"
|
7
|
-
exit 0
|
8
|
-
end
|
6
|
+
require 'optparse'
|
9
7
|
|
10
|
-
|
8
|
+
options = {
|
9
|
+
:ip => "0.0.0.0:7878",
|
10
|
+
}
|
11
|
+
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
|
14
|
+
opts.on("-f file", "File will be parsed") do |v|
|
15
|
+
options[:file] = v
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on("-i ip", "--ip ip", "client or server : 0.0.0.0 or 0.0.0.0:7878", "default is 0.0.0.0:7878") do |v|
|
19
|
+
options[:ip] = v
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-n device_name", "--name device_name", "Send or Recv device name") do |v|
|
23
|
+
options[:device_name] = v
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on_tail("--show", "Show all devices name and exit") do
|
27
|
+
require 'diy/device_finder'
|
28
|
+
DIY::DeviceFinder.pp_devices
|
29
|
+
exit 0
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on_tail('-v','--version', 'Show version') do
|
33
|
+
puts DIY::PCAP::VERSION
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on_tail('-V', 'detail mode') do
|
38
|
+
DIY::Logger.level = ::Logger::DEBUG
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on_tail('-h','--help', 'Show this help') do
|
42
|
+
puts opts
|
43
|
+
exit 0
|
44
|
+
end
|
45
|
+
end.parse!
|
46
|
+
|
47
|
+
if options[:file]
|
48
|
+
require File.join( Dir.pwd, options[:file] )
|
49
|
+
else
|
50
|
+
ip = options[:ip]
|
51
|
+
if ip.include?(':')
|
52
|
+
uri = "druby://#{ip}"
|
53
|
+
else
|
54
|
+
uri = "druby://#{ip}:7878"
|
55
|
+
end
|
56
|
+
|
57
|
+
if options[:device_name]
|
58
|
+
device_name = options[:device_name]
|
59
|
+
else
|
60
|
+
require 'diy/device_finder'
|
61
|
+
device_name = DIY::DeviceFinder.smart_select
|
62
|
+
end
|
63
|
+
DIY::Logger.info( "Initialize Live: #{device_name}" )
|
64
|
+
device = FFI::PCap::Live.new(:dev=>device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
65
|
+
worker = DIY::Worker.new(device)
|
66
|
+
DIY::WorkerKeeper.new(worker, uri).run
|
67
|
+
end
|
data/bin/rpcap
CHANGED
@@ -1,12 +1,68 @@
|
|
1
1
|
$LOAD_PATH.unshift File.join( File.dirname(__FILE__), '..', 'lib' )
|
2
|
+
require 'rubygems'
|
2
3
|
require 'diy-pcap'
|
3
4
|
require 'diy/task'
|
4
5
|
|
5
|
-
|
6
|
+
require 'optparse'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
8
|
+
options = {
|
9
|
+
:ip => "0.0.0.0:7879",
|
10
|
+
}
|
11
11
|
|
12
|
-
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
|
14
|
+
opts.on("-f file", "File will be parsed") do |v|
|
15
|
+
options[:file] = v
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on("-i ip", "--ip ip", "client or server : 0.0.0.0 or 0.0.0.0:7879", "default is 0.0.0.0:7879") do |v|
|
19
|
+
options[:ip] = v
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-n device_name", "--name device_name", "Send or Recv device name") do |v|
|
23
|
+
options[:device_name] = v
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on_tail("--show", "Show all devices name and exit") do
|
27
|
+
require 'diy/device_finder'
|
28
|
+
DIY::DeviceFinder.pp_devices
|
29
|
+
exit 0
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on_tail('-v','--version', 'Show version') do
|
33
|
+
puts DIY::PCAP::VERSION
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on_tail('-V', 'detail mode') do
|
38
|
+
DIY::Logger.level = ::Logger::DEBUG
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on_tail('-h','--help', 'Show this help') do
|
42
|
+
puts opts
|
43
|
+
exit 0
|
44
|
+
end
|
45
|
+
end.parse!
|
46
|
+
|
47
|
+
if options[:file]
|
48
|
+
$SERVER = true
|
49
|
+
require File.join( Dir.pwd, options[:file])
|
50
|
+
else
|
51
|
+
ip = options[:ip]
|
52
|
+
if ip.include?(':')
|
53
|
+
uri = "druby://#{ip}"
|
54
|
+
else
|
55
|
+
uri = "druby://#{ip}:7879"
|
56
|
+
end
|
57
|
+
|
58
|
+
if options[:device_name]
|
59
|
+
device_name = options[:device_name]
|
60
|
+
else
|
61
|
+
require 'diy/device_finder'
|
62
|
+
device_name = DIY::DeviceFinder.smart_select
|
63
|
+
end
|
64
|
+
DIY::Logger.info( "Initialize Live: #{device_name}" )
|
65
|
+
device = FFI::PCap::Live.new(:dev=>device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
66
|
+
worker = DIY::Worker.new(device)
|
67
|
+
DIY::WorkerKeeper.new(worker, uri).run
|
68
|
+
end
|
data/lib/diy/builder.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'drb'
|
1
2
|
module DIY
|
2
3
|
class Builder
|
3
4
|
def initialize(server = false, &block)
|
@@ -6,16 +7,6 @@ module DIY
|
|
6
7
|
@server = server
|
7
8
|
end
|
8
9
|
|
9
|
-
def find_device
|
10
|
-
@device_name ||= FFI::PCap.dump_devices[0][0]
|
11
|
-
DIY::Logger.info( "Initialize Live: #{@device_name}" )
|
12
|
-
@live = FFI::PCap::Live.new(:dev=>@device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
13
|
-
end
|
14
|
-
|
15
|
-
def device(name)
|
16
|
-
@device_name = name
|
17
|
-
end
|
18
|
-
|
19
10
|
def use(what)
|
20
11
|
@strategies.unshift(what)
|
21
12
|
end
|
@@ -24,6 +15,14 @@ module DIY
|
|
24
15
|
@before_send_hook = block
|
25
16
|
end
|
26
17
|
|
18
|
+
def find_worker_keepers
|
19
|
+
@curi ||= "druby://localhost:7878"
|
20
|
+
@suri ||= "druby://localhost:7879"
|
21
|
+
DRb.start_service
|
22
|
+
@client = DRbObject.new_with_uri(@curi)
|
23
|
+
@server = DRbObject.new_with_uri(@suri)
|
24
|
+
end
|
25
|
+
|
27
26
|
def pcapfile(pcaps)
|
28
27
|
DIY::Logger.info( "Initialize Offline: #{pcaps.to_a.join(', ')}" )
|
29
28
|
@offline = DIY::Offline.new(pcaps)
|
@@ -31,13 +30,12 @@ module DIY
|
|
31
30
|
alias pcapfiles pcapfile
|
32
31
|
|
33
32
|
def run
|
34
|
-
@offline ||=
|
35
|
-
@
|
36
|
-
@strategy_builder = DIY::StrategyBuilder.new(@queue)
|
33
|
+
@offline ||= DIY::Offline.new('pcaps/example.pcap')
|
34
|
+
@strategy_builder = DIY::StrategyBuilder.new
|
37
35
|
@strategies.each { |builder| @strategy_builder.add(builder) }
|
38
|
-
|
39
|
-
controller = Controller.new( @
|
40
|
-
controller.before_send(&@before_send_hook)
|
36
|
+
find_worker_keepers
|
37
|
+
controller = Controller.new( @client, @server, @offline, @strategy_builder )
|
38
|
+
#~ controller.before_send(&@before_send_hook)
|
41
39
|
controller.run
|
42
40
|
end
|
43
41
|
|
data/lib/diy/controller.rb
CHANGED
@@ -1,46 +1,63 @@
|
|
1
1
|
# encoding : utf-8
|
2
|
+
|
3
|
+
require 'timeout'
|
2
4
|
module DIY
|
3
5
|
class Controller
|
4
|
-
def initialize(
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@sender = Sender.new(@live)
|
10
|
-
@queue = strategy.queue
|
11
|
-
@logger = DIY::Logger
|
12
|
-
end
|
13
|
-
attr_accessor :logger
|
14
|
-
|
15
|
-
def before_send(&block)
|
16
|
-
@sender.before_send(&block)
|
6
|
+
def initialize( client, server, offline, strategy)
|
7
|
+
@client = client
|
8
|
+
@server = server
|
9
|
+
@offline = offline
|
10
|
+
@strategy = strategy
|
17
11
|
end
|
18
12
|
|
19
13
|
def run
|
20
|
-
|
21
|
-
|
22
|
-
@recver.run
|
23
|
-
end
|
14
|
+
client = @client
|
15
|
+
server = @server
|
24
16
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@recver_t.join
|
31
|
-
rescue HopePacketTimeoutError =>e
|
32
|
-
# next offline
|
33
|
-
DIY::Logger.warn("Timeout: #{e}")
|
34
|
-
old = e
|
17
|
+
#clear
|
18
|
+
client.terminal
|
19
|
+
server.terminal
|
20
|
+
|
21
|
+
loop do
|
35
22
|
begin
|
36
|
-
|
37
|
-
|
23
|
+
pkts = @offline.nexts
|
24
|
+
one_round( client, server, pkts )
|
25
|
+
client, server = server, client
|
26
|
+
rescue HopePacketTimeoutError
|
27
|
+
DIY::Logger.warn( "Timeout: Hope packet is #{pkts[0].inspect} ")
|
28
|
+
@offline.next_pcap
|
29
|
+
client,server = @client, @server
|
38
30
|
rescue EOFError
|
39
|
-
|
40
|
-
|
31
|
+
client.terminal
|
32
|
+
server.terminal
|
33
|
+
break
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def one_round( client, server, pkts )
|
39
|
+
@round_count = 0 unless @round_count
|
40
|
+
@round_count += 1
|
41
|
+
DIY::Logger.info "round #{@round_count}: #{client} #{server} #{pkts[0].inspect}:(size= #{pkts.size})"
|
42
|
+
server.ready do |recv_pkt|
|
43
|
+
recv_pkt = Packet.new(recv_pkt)
|
44
|
+
@strategy.call(pkts.first, recv_pkt, pkts)
|
45
|
+
end
|
46
|
+
client.inject(pkts)
|
47
|
+
wait_recv_ok(pkts)
|
48
|
+
server.terminal
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_recv_ok(pkts)
|
52
|
+
wait_until { pkts.empty? }
|
53
|
+
end
|
54
|
+
|
55
|
+
def wait_until( timeout = 20, &block )
|
56
|
+
timeout(timeout, DIY::HopePacketTimeoutError.new("hope packet wait timeout after #{timeout} senconds") ) do
|
57
|
+
loop do
|
58
|
+
break if block.call
|
59
|
+
sleep 0.01
|
41
60
|
end
|
42
|
-
rescue EOFError
|
43
|
-
@recver.stop
|
44
61
|
end
|
45
62
|
end
|
46
63
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DIY
|
2
|
+
class DeviceFinder
|
3
|
+
class <<self
|
4
|
+
def smart_select
|
5
|
+
ret = devices.find do |device, net|
|
6
|
+
!device.match(/dialup/) && net != nil
|
7
|
+
end
|
8
|
+
if ret
|
9
|
+
ret[0]
|
10
|
+
else
|
11
|
+
devices[0]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def pp_devices
|
16
|
+
devices.each do |device, net|
|
17
|
+
printf "%20s\t:\t%s\n", device, net
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def devices
|
22
|
+
FFI::PCap.dump_devices
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/diy/dig.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'diy/exceptions'
|
2
2
|
require 'diy/logger'
|
3
3
|
require 'diy/utils'
|
4
|
+
require 'diy/packet'
|
4
5
|
require 'diy/offline'
|
5
|
-
require 'diy/
|
6
|
-
require 'diy/sender'
|
7
|
-
require 'diy/queue'
|
8
|
-
require 'diy/strategy'
|
9
|
-
require 'diy/strategy_builder'
|
6
|
+
require 'diy/builder'
|
10
7
|
require 'diy/controller'
|
11
|
-
require 'diy/
|
8
|
+
require 'diy/strategy_builder'
|
9
|
+
require 'diy/strategy'
|
10
|
+
|
11
|
+
require 'diy/worker'
|
12
|
+
require 'diy/worker_keeper'
|
data/lib/diy/logger.rb
CHANGED
data/lib/diy/offline.rb
CHANGED
@@ -2,56 +2,126 @@
|
|
2
2
|
|
3
3
|
module DIY
|
4
4
|
class Offline
|
5
|
-
def initialize(
|
6
|
-
@
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@position = 0
|
13
|
-
end
|
14
|
-
@new_pcap = true
|
5
|
+
def initialize( pcap_files )
|
6
|
+
@pcap_files = [ pcap_files ] if pcap_files.kind_of?(String)
|
7
|
+
@pcap_files ||= pcap_files
|
8
|
+
@off = FFI::PCap::Offline.new(@pcap_files[0])
|
9
|
+
# 记录文件在目录中的位置
|
10
|
+
@position = 0
|
11
|
+
# 记录包在当前文件的位置
|
15
12
|
@num = 0
|
13
|
+
|
14
|
+
@tmp_pcap = nil
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
|
17
|
+
def nexts
|
18
|
+
ret = []
|
19
|
+
# 取一个
|
20
|
+
pkt = fetch_one
|
20
21
|
if pkt.nil?
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
next_pcap
|
23
|
+
pkt = fetch_one
|
24
|
+
end
|
25
|
+
|
26
|
+
ret << pkt
|
27
|
+
op = "=="
|
28
|
+
if ! fetch_cached_mac
|
29
|
+
cached_mac(pkt)
|
30
|
+
else
|
31
|
+
if Utils.src_mac(pkt) != fetch_cached_mac
|
32
|
+
op = "!="
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
29
|
-
|
30
|
-
|
36
|
+
loop do
|
37
|
+
pkt = self.next
|
38
|
+
if pkt.nil?
|
39
|
+
return ret
|
40
|
+
end
|
41
|
+
|
42
|
+
if compare_mac( op, Utils.src_mac(pkt), fetch_cached_mac)
|
43
|
+
ret << pkt
|
44
|
+
else
|
45
|
+
cached(pkt)
|
46
|
+
return ret
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
31
50
|
|
51
|
+
end
|
52
|
+
|
53
|
+
def compare_mac( op, mac1, mac2)
|
54
|
+
if op == "=="
|
55
|
+
mac1 == mac2
|
56
|
+
elsif op == "!="
|
57
|
+
mac1 != mac2
|
58
|
+
else
|
59
|
+
raise "error op"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def fetch_one
|
64
|
+
pkt = fetch_cache
|
65
|
+
if pkt.nil?
|
66
|
+
pkt = self.next
|
67
|
+
end
|
32
68
|
pkt
|
33
69
|
end
|
70
|
+
protected
|
71
|
+
# 只处理当前文件
|
72
|
+
def next
|
73
|
+
pkt = @off.next
|
74
|
+
@num += 1
|
75
|
+
return nil if pkt.nil?
|
76
|
+
|
77
|
+
return Packet.new(pkt.copy.body, fullname)
|
78
|
+
end
|
79
|
+
|
80
|
+
def cached(pkt)
|
81
|
+
raise "Can't cached one pkt twice" if @tmp_pcap
|
82
|
+
@tmp_pcap = pkt
|
83
|
+
end
|
84
|
+
|
85
|
+
def cached_mac(pkt)
|
86
|
+
@src = Utils.src_mac(pkt)
|
87
|
+
end
|
88
|
+
|
89
|
+
def fetch_cached_mac
|
90
|
+
@src
|
91
|
+
end
|
92
|
+
|
93
|
+
def clear_cached_mac
|
94
|
+
@src = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def fetch_cache
|
98
|
+
if @tmp_pcap
|
99
|
+
tmp = @tmp_pcap
|
100
|
+
@tmp_pcap = nil
|
101
|
+
return tmp
|
102
|
+
end
|
103
|
+
return nil
|
104
|
+
end
|
34
105
|
|
35
106
|
def first_pkt?
|
107
|
+
puts @num
|
36
108
|
@num == 1
|
37
109
|
end
|
38
|
-
|
110
|
+
public
|
39
111
|
def next_pcap
|
40
|
-
if @
|
112
|
+
if @position >= @pcap_files.size - 1
|
41
113
|
raise EOFError, " end of pcaps "
|
42
114
|
end
|
43
115
|
@position += 1
|
44
|
-
DIY::Logger.info("pcap file changed: #{@
|
45
|
-
@off = FFI::PCap::Offline.new(@
|
116
|
+
DIY::Logger.info("pcap file changed: #{@pcap_files[@position]}")
|
117
|
+
@off = FFI::PCap::Offline.new(@pcap_files[@position])
|
46
118
|
@num = 0
|
119
|
+
clear_cached_mac
|
120
|
+
fetch_cache
|
47
121
|
end
|
48
122
|
|
49
123
|
def filename
|
50
|
-
|
51
|
-
@file_or_files
|
52
|
-
else
|
53
|
-
@file_or_files[@position]
|
54
|
-
end
|
124
|
+
@pcap_files[@position]
|
55
125
|
end
|
56
126
|
|
57
127
|
def fullname
|