DIY-pcap 0.0.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|