DIY-pcap 0.0.2 → 0.0.3
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/lib/diy/builder.rb +41 -0
- data/lib/diy/controller.rb +40 -0
- data/lib/diy/dig.rb +10 -336
- data/lib/diy/exceptions.rb +8 -0
- data/lib/diy/logger.rb +31 -0
- data/lib/diy/queue.rb +131 -0
- data/lib/diy/recver.rb +33 -0
- data/lib/diy/sender.rb +26 -0
- data/lib/diy/strategy.rb +40 -0
- data/lib/diy/strategy_builder.rb +60 -0
- data/lib/diy/utils.rb +18 -0
- data/lib/diy/version.rb +1 -1
- data/simple/diy-strategy-pcap.rb +21 -0
- data/spec/builder_spec.rb +7 -0
- data/spec/logger_spec.rb +7 -0
- data/spec/{dig_spec.rb → queue_spec.rb} +0 -26
- data/spec/sender_spec.rb +21 -0
- metadata +24 -8
data/lib/diy/builder.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module DIY
|
2
|
+
class Builder
|
3
|
+
def initialize(&block)
|
4
|
+
@strategies = []
|
5
|
+
instance_eval(&block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def find_device
|
9
|
+
@device_name ||= FFI::PCap.dump_devices[0][0]
|
10
|
+
@live = FFI::PCap::Live.new(:dev=>@device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
11
|
+
end
|
12
|
+
|
13
|
+
def device(name)
|
14
|
+
@device_name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def use(what)
|
18
|
+
@strategies.unshift(what)
|
19
|
+
end
|
20
|
+
|
21
|
+
def before_send(&block)
|
22
|
+
@before_send_hook = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def pcapfile(pcaps)
|
26
|
+
@offline = FFI::PCap::Offline.new(pcaps)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
@offline ||= FFI::PCap::Offline.new('pcaps/example.pcap')
|
31
|
+
@queue = Queue.new(@offline)
|
32
|
+
@strategy_builder = DIY::StrategyBuilder.new(@queue)
|
33
|
+
@strategies.each { |builder| @strategy_builder.add(builder) }
|
34
|
+
find_device
|
35
|
+
controller = Controller.new( @live, @offline, @strategy_builder )
|
36
|
+
controller.before_send(&@before_send_hook)
|
37
|
+
controller.run
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding : utf-8
|
2
|
+
module DIY
|
3
|
+
class Controller
|
4
|
+
def initialize(live, offline, strategy)
|
5
|
+
@live = live
|
6
|
+
@recver = Recver.new(@live)
|
7
|
+
@recver.add_watcher(strategy)
|
8
|
+
@recver_t = nil
|
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)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
# 接收线程
|
21
|
+
@recver_t = Thread.new do
|
22
|
+
@recver.run
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
@queue.do_loop do |pkt|
|
27
|
+
@sender.inject(pkt)
|
28
|
+
end
|
29
|
+
@recver_t.join
|
30
|
+
rescue HopePacketTimeoutError
|
31
|
+
# next offline
|
32
|
+
raise
|
33
|
+
rescue EOFError
|
34
|
+
@recver.stop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/lib/diy/dig.rb
CHANGED
@@ -1,337 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
class Error < RuntimeError; end
|
5
|
-
# 数据包读取完毕
|
6
|
-
class EOFError < Error; end
|
1
|
+
require 'diy/exceptions'
|
2
|
+
require 'diy/logger'
|
3
|
+
require 'diy/utils'
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@live.loop do |this, pkt|
|
16
|
-
notify_recv_pkt(pkt)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def stop
|
21
|
-
@live.stop
|
22
|
-
end
|
23
|
-
|
24
|
-
def notify_recv_pkt(pkt)
|
25
|
-
@watchers.each do |watcher|
|
26
|
-
watcher.recv_pkt(pkt.body)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def add_watcher(watcher)
|
31
|
-
@watchers = [] unless @watchers
|
32
|
-
@watchers << watcher
|
33
|
-
end
|
34
|
-
|
35
|
-
def del_watcher(watcher)
|
36
|
-
@watchers.delete(watcher)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class Sender
|
41
|
-
def initialize(live)
|
42
|
-
@live = live
|
43
|
-
end
|
44
|
-
|
45
|
-
def inject(pkt)
|
46
|
-
puts "send: #{Time.now}"
|
47
|
-
@live.inject(pkt)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
require 'thread'
|
52
|
-
require 'timeout'
|
53
|
-
class Queue
|
54
|
-
|
55
|
-
def initialize(offline)
|
56
|
-
@expect_recv_queue = []
|
57
|
-
@offline = offline
|
58
|
-
@m = Mutex.new
|
59
|
-
# 暂存 next_send_pkt 数据
|
60
|
-
@tmp_send_pkt = nil
|
61
|
-
end
|
62
|
-
|
63
|
-
def expect_recv_queue
|
64
|
-
@expect_recv_queue
|
65
|
-
end
|
66
|
-
|
67
|
-
def pop
|
68
|
-
return nil if @expect_recv_queue.empty?
|
69
|
-
@m.synchronize {
|
70
|
-
return @expect_recv_queue.shift
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
74
|
-
def delete(what)
|
75
|
-
if @expect_recv_queue.include?(what)
|
76
|
-
@m.synchronize {
|
77
|
-
if @expect_recv_queue.include?(what)
|
78
|
-
return @expect_recv_queue.delete(what)
|
79
|
-
end
|
80
|
-
}
|
81
|
-
end
|
82
|
-
return nil
|
83
|
-
end
|
84
|
-
|
85
|
-
def delete_at(index)
|
86
|
-
@m.synchronize {
|
87
|
-
return @expect_recv_queue.delete_at(index)
|
88
|
-
}
|
89
|
-
end
|
90
|
-
|
91
|
-
def peek
|
92
|
-
return nil if @expect_recv_queue.empty?
|
93
|
-
@expect_recv_queue[0]
|
94
|
-
end
|
95
|
-
|
96
|
-
# 处理发送报文
|
97
|
-
#
|
98
|
-
# 等待接受报文完成后, 返回发送报文, 并重新填充接受报文
|
99
|
-
# TODO: 支持多个pcap文件
|
100
|
-
def next_send_pkt(&block)
|
101
|
-
wait_until { @expect_recv_queue.empty? }
|
102
|
-
if @tmp_send_pkt
|
103
|
-
pkt = @tmp_send_pkt
|
104
|
-
@tmp_send_pkt = nil
|
105
|
-
else
|
106
|
-
pkt = write_recv_pkt
|
107
|
-
wait_until { @expect_recv_queue.empty? }
|
108
|
-
end
|
109
|
-
raise EOFError, " no pkt to send" unless pkt
|
110
|
-
pkt = pkt.copy
|
111
|
-
|
112
|
-
recv_pkt = write_recv_pkt
|
113
|
-
|
114
|
-
yield(pkt.body) if block_given?
|
115
|
-
|
116
|
-
@tmp_send_pkt = recv_pkt.copy if recv_pkt
|
117
|
-
pkt.body
|
118
|
-
end
|
119
|
-
alias_method :next, :next_send_pkt
|
120
|
-
|
121
|
-
def write_recv_pkt
|
122
|
-
while ( (recv_pkt = @offline.next) && ( set_first_gout(recv_pkt.body); comein?(recv_pkt.body) ) )
|
123
|
-
@m.synchronize {
|
124
|
-
@expect_recv_queue << recv_pkt.copy.body
|
125
|
-
}
|
126
|
-
end
|
127
|
-
recv_pkt
|
128
|
-
end
|
129
|
-
|
130
|
-
def do_loop(&block)
|
131
|
-
raise "Must give me block" unless block_given?
|
132
|
-
while(true) do
|
133
|
-
next_send_pkt(&block)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def set_first_gout(pkt)
|
138
|
-
return @src_mac if @src_mac
|
139
|
-
if pkt.size < 12
|
140
|
-
raise PktError,"can't find src mac: error format packet"
|
141
|
-
end
|
142
|
-
@src_mac = pkt[6..11]
|
143
|
-
end
|
144
|
-
|
145
|
-
def comein?(pkt)
|
146
|
-
ret = judge_direct(pkt) do | pkt_mac, src_mac|
|
147
|
-
(pkt_mac != src_mac) ^ server?
|
148
|
-
end
|
149
|
-
ret
|
150
|
-
end
|
151
|
-
|
152
|
-
def gout?(pkt)
|
153
|
-
judge_direct(pkt) do | pkt_mac, src_mac|
|
154
|
-
(pkt_mac == src_mac) ^ server?
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def server?
|
159
|
-
$SERVER
|
160
|
-
end
|
161
|
-
|
162
|
-
def judge_direct(pkt,&block)
|
163
|
-
if pkt.size < 12
|
164
|
-
raise PktError,"can't find src mac: error format packet"
|
165
|
-
end
|
166
|
-
raise "src_mac not set" unless @src_mac
|
167
|
-
yield( pkt[6..11], @src_mac )
|
168
|
-
end
|
169
|
-
|
170
|
-
def wait_until( timeout = 20, &block )
|
171
|
-
timeout(timeout) do
|
172
|
-
loop do
|
173
|
-
break if block.call
|
174
|
-
sleep 0.01
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
# 这个策略是一个最基本的:
|
182
|
-
# 具体返回值含义见 @BasicStrategy
|
183
|
-
class Strategy
|
184
|
-
OK = true
|
185
|
-
OK_NO_POP = 1
|
186
|
-
FAIL = false
|
187
|
-
NONE = nil
|
188
|
-
end
|
189
|
-
|
190
|
-
class BasicStrategy < Strategy
|
191
|
-
|
192
|
-
# @argument:
|
193
|
-
# hope_pkt: 期望的报文
|
194
|
-
# recv_pkt: 接收的报文
|
195
|
-
# queue: 期望接收队列, 如果期望乱序时,你可以使用这个参数
|
196
|
-
#
|
197
|
-
# @return:
|
198
|
-
# OK : 匹配, 可以进行下一个报文的处理
|
199
|
-
# OK_NO_POP: 匹配了接收队列中的报文, 但是不需要框架自动pop掉期望报文( 注意, 你需要自行处于报文 )
|
200
|
-
# FAIL: 肯定失败时使用
|
201
|
-
# NONE: 不匹配, 让框架进行下一个报文匹配
|
202
|
-
def call(hope_pkt, recv_pkt, queue)
|
203
|
-
raise "write code here"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
class SimpleStrategy < BasicStrategy
|
208
|
-
def call(hope_pkt, recv_pkt, queue)
|
209
|
-
if hope_pkt == recv_pkt
|
210
|
-
return OK
|
211
|
-
else
|
212
|
-
return NONE
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
require 'logger'
|
218
|
-
class StrategyBuilder
|
219
|
-
def initialize(queue)
|
220
|
-
@ins = []
|
221
|
-
@logger = Logger.new(STDOUT)
|
222
|
-
@queue = queue
|
223
|
-
end
|
224
|
-
attr_reader :queue
|
225
|
-
|
226
|
-
def add(strategy)
|
227
|
-
@ins << strategy
|
228
|
-
end
|
229
|
-
alias << add
|
230
|
-
|
231
|
-
def logger=(logger)
|
232
|
-
@logger = logger
|
233
|
-
end
|
234
|
-
|
235
|
-
def logger
|
236
|
-
@logger
|
237
|
-
end
|
238
|
-
|
239
|
-
def recv_pkt(pkt)
|
240
|
-
recv_pkt_queue(queue,pkt)
|
241
|
-
end
|
242
|
-
|
243
|
-
def recv_pkt_queue(queue, recv_pkt)
|
244
|
-
hope_pkt = queue.peek
|
245
|
-
logger.debug("recv_pkt, I hope: #{ hope_pkt[0..10].dump rescue nil }...")
|
246
|
-
return if hope_pkt.nil?
|
247
|
-
@ins.each do |strategy|
|
248
|
-
begin
|
249
|
-
ret = strategy.call(hope_pkt, recv_pkt, queue)
|
250
|
-
rescue Exception => e
|
251
|
-
logger.error("strategy call exception: #{e.class} -> #{e.message}")
|
252
|
-
raise
|
253
|
-
#仅仅忽略
|
254
|
-
else
|
255
|
-
if ret == Strategy::OK
|
256
|
-
logger.info("pkt same:")
|
257
|
-
queue.pop
|
258
|
-
return
|
259
|
-
elsif ret == Strategy::OK_NO_POP
|
260
|
-
logger.info("pkt same but no pop:")
|
261
|
-
return
|
262
|
-
elsif ret == Strategy::FAIL
|
263
|
-
logger.warn("pkt fail:")
|
264
|
-
elsif ret == Strategy::NONE
|
265
|
-
logger.debug("pkt jumpped:")
|
266
|
-
next
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
|
274
|
-
class Controller
|
275
|
-
def initialize(live, offline, strategy)
|
276
|
-
@live = live
|
277
|
-
@recver = Recver.new(@live)
|
278
|
-
@recver.add_watcher(strategy)
|
279
|
-
@recver_t = nil
|
280
|
-
@sender = Sender.new(@live)
|
281
|
-
@queue = strategy.queue
|
282
|
-
@logger = Logger.new(STDOUT)
|
283
|
-
end
|
284
|
-
attr_accessor :logger
|
285
|
-
|
286
|
-
def run
|
287
|
-
@recver_t = Thread.new do
|
288
|
-
@recver.run
|
289
|
-
end
|
290
|
-
|
291
|
-
begin
|
292
|
-
@queue.do_loop do |pkt|
|
293
|
-
@sender.inject(pkt)
|
294
|
-
end
|
295
|
-
@recver_t.join
|
296
|
-
rescue EOFError
|
297
|
-
@recver.stop
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
end
|
302
|
-
|
303
|
-
class Builder
|
304
|
-
def initialize(&block)
|
305
|
-
@strategies = []
|
306
|
-
instance_eval(&block)
|
307
|
-
end
|
308
|
-
|
309
|
-
def find_device
|
310
|
-
@device_name ||= FFI::PCap.dump_devices[0][0]
|
311
|
-
@live = FFI::PCap::Live.new(:dev=>@device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
312
|
-
end
|
313
|
-
|
314
|
-
def device(name)
|
315
|
-
@device_name = name
|
316
|
-
end
|
317
|
-
|
318
|
-
def use(what)
|
319
|
-
@strategies.unshift(what)
|
320
|
-
end
|
321
|
-
|
322
|
-
def pcapfile(pcaps)
|
323
|
-
@offline = FFI::PCap::Offline.new(pcaps)
|
324
|
-
end
|
325
|
-
|
326
|
-
def run
|
327
|
-
@offline ||= FFI::PCap::Offline.new('pcaps/example.pcap')
|
328
|
-
@queue = Queue.new(@offline)
|
329
|
-
@strategy_builder = DIY::StrategyBuilder.new(@queue)
|
330
|
-
@strategies.each { |builder| @strategy_builder.add(builder) }
|
331
|
-
find_device
|
332
|
-
controller = Controller.new( @live, @offline, @strategy_builder )
|
333
|
-
controller.run
|
334
|
-
end
|
335
|
-
|
336
|
-
end
|
337
|
-
end
|
5
|
+
require 'diy/recver'
|
6
|
+
require 'diy/sender'
|
7
|
+
require 'diy/queue'
|
8
|
+
require 'diy/strategy'
|
9
|
+
require 'diy/strategy_builder'
|
10
|
+
require 'diy/controller'
|
11
|
+
require 'diy/builder'
|
data/lib/diy/logger.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module DIY
|
4
|
+
class Logger
|
5
|
+
@@logger = ::Logger.new(STDOUT)
|
6
|
+
@@logger.level = ::Logger::DEBUG
|
7
|
+
@@logger.datetime_format = "%d-%b-%Y %H:%M:%S"
|
8
|
+
class <<self
|
9
|
+
def debug(*arg)
|
10
|
+
@@logger.debug(*arg)
|
11
|
+
end
|
12
|
+
|
13
|
+
def info(*arg)
|
14
|
+
@@logger.info(*arg)
|
15
|
+
end
|
16
|
+
|
17
|
+
def warn(*arg)
|
18
|
+
@@logger.warn(*arg)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(*arg)
|
22
|
+
@@logger.error(*arg)
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(logger)
|
26
|
+
@@logger = logger
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/diy/queue.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'timeout'
|
3
|
+
module DIY
|
4
|
+
class Queue
|
5
|
+
|
6
|
+
def initialize(offline)
|
7
|
+
@expect_recv_queue = []
|
8
|
+
@offline = offline
|
9
|
+
@m = Mutex.new
|
10
|
+
# 暂存 next_send_pkt 数据
|
11
|
+
@tmp_send_pkt = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def expect_recv_queue
|
15
|
+
@expect_recv_queue
|
16
|
+
end
|
17
|
+
|
18
|
+
def pop
|
19
|
+
return nil if @expect_recv_queue.empty?
|
20
|
+
@m.synchronize {
|
21
|
+
return @expect_recv_queue.shift
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(what)
|
26
|
+
if @expect_recv_queue.include?(what)
|
27
|
+
@m.synchronize {
|
28
|
+
if @expect_recv_queue.include?(what)
|
29
|
+
return @expect_recv_queue.delete(what)
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_at(index)
|
37
|
+
@m.synchronize {
|
38
|
+
return @expect_recv_queue.delete_at(index)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def peek
|
43
|
+
return nil if @expect_recv_queue.empty?
|
44
|
+
@expect_recv_queue[0]
|
45
|
+
end
|
46
|
+
|
47
|
+
# 处理发送报文
|
48
|
+
#
|
49
|
+
# 等待接受报文完成后, 返回发送报文, 并重新填充接受报文
|
50
|
+
# TODO: 支持多个pcap文件
|
51
|
+
def next_send_pkt(&block)
|
52
|
+
wait_until { @expect_recv_queue.empty? }
|
53
|
+
if @tmp_send_pkt
|
54
|
+
pkt = @tmp_send_pkt
|
55
|
+
@tmp_send_pkt = nil
|
56
|
+
else
|
57
|
+
pkt = write_recv_pkt
|
58
|
+
wait_until { @expect_recv_queue.empty? }
|
59
|
+
end
|
60
|
+
raise EOFError, " no pkt to send" unless pkt
|
61
|
+
pkt = pkt.copy
|
62
|
+
|
63
|
+
recv_pkt = write_recv_pkt
|
64
|
+
|
65
|
+
yield(pkt.body) if block_given?
|
66
|
+
|
67
|
+
@tmp_send_pkt = recv_pkt.copy if recv_pkt
|
68
|
+
pkt.body
|
69
|
+
end
|
70
|
+
alias_method :next, :next_send_pkt
|
71
|
+
|
72
|
+
def write_recv_pkt
|
73
|
+
while ( (recv_pkt = @offline.next) && ( set_first_gout(recv_pkt.body); comein?(recv_pkt.body) ) )
|
74
|
+
@m.synchronize {
|
75
|
+
@expect_recv_queue << recv_pkt.copy.body
|
76
|
+
}
|
77
|
+
end
|
78
|
+
recv_pkt
|
79
|
+
end
|
80
|
+
|
81
|
+
def do_loop(&block)
|
82
|
+
raise "Must give me block" unless block_given?
|
83
|
+
while(true) do
|
84
|
+
next_send_pkt(&block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_first_gout(pkt)
|
89
|
+
return @src_mac if @src_mac
|
90
|
+
if pkt.size < 12
|
91
|
+
raise PktError,"can't find src mac: error format packet"
|
92
|
+
end
|
93
|
+
@src_mac = pkt[6..11]
|
94
|
+
end
|
95
|
+
|
96
|
+
def comein?(pkt)
|
97
|
+
ret = judge_direct(pkt) do | pkt_mac, src_mac|
|
98
|
+
(pkt_mac != src_mac) ^ server?
|
99
|
+
end
|
100
|
+
ret
|
101
|
+
end
|
102
|
+
|
103
|
+
def gout?(pkt)
|
104
|
+
judge_direct(pkt) do | pkt_mac, src_mac|
|
105
|
+
(pkt_mac == src_mac) ^ server?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def server?
|
110
|
+
$SERVER
|
111
|
+
end
|
112
|
+
|
113
|
+
def judge_direct(pkt,&block)
|
114
|
+
if pkt.size < 12
|
115
|
+
raise PktError,"can't find src mac: error format packet"
|
116
|
+
end
|
117
|
+
raise "src_mac not set" unless @src_mac
|
118
|
+
yield( pkt[6..11], @src_mac )
|
119
|
+
end
|
120
|
+
|
121
|
+
def wait_until( timeout = 20, &block )
|
122
|
+
timeout(timeout, DIY::HopePacketTimeoutError.new("hope packet wait timeout after #{timeout} senconds") ) do
|
123
|
+
loop do
|
124
|
+
break if block.call
|
125
|
+
sleep 0.01
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end # end Queue
|
131
|
+
end
|
data/lib/diy/recver.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module DIY
|
2
|
+
class Recver
|
3
|
+
def initialize(live)
|
4
|
+
@live = live
|
5
|
+
@watchers = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
@live.loop do |this, pkt|
|
10
|
+
notify_recv_pkt(pkt)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def stop
|
15
|
+
@live.stop
|
16
|
+
end
|
17
|
+
|
18
|
+
def notify_recv_pkt(pkt)
|
19
|
+
@watchers.each do |watcher|
|
20
|
+
watcher.recv_pkt(pkt.body)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_watcher(watcher)
|
25
|
+
@watchers = [] unless @watchers
|
26
|
+
@watchers << watcher
|
27
|
+
end
|
28
|
+
|
29
|
+
def del_watcher(watcher)
|
30
|
+
@watchers.delete(watcher)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/diy/sender.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module DIY
|
2
|
+
class Sender
|
3
|
+
def initialize(live)
|
4
|
+
@live = live
|
5
|
+
@before_send_hook = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def inject(pkt)
|
9
|
+
pkt = before_send_call(pkt)
|
10
|
+
@live.inject(pkt)
|
11
|
+
end
|
12
|
+
|
13
|
+
def before_send(&block)
|
14
|
+
@before_send_hook = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_send_call(pkt)
|
18
|
+
if @before_send_hook
|
19
|
+
@before_send_hook.call(pkt)
|
20
|
+
else
|
21
|
+
pkt
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/diy/strategy.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module DIY
|
2
|
+
# 这个策略是一个最基本的:
|
3
|
+
# 具体返回值含义见 @BasicStrategy
|
4
|
+
class Strategy
|
5
|
+
OK = true
|
6
|
+
OK_NO_POP = 1
|
7
|
+
FAIL = false
|
8
|
+
NONE = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
class BasicStrategy < Strategy
|
12
|
+
|
13
|
+
# @argument:
|
14
|
+
# hope_pkt: 期望的报文
|
15
|
+
# recv_pkt: 接收的报文
|
16
|
+
# queue: 期望接收队列, 如果期望乱序时,你可以使用这个参数
|
17
|
+
#
|
18
|
+
# @return:
|
19
|
+
# OK : 匹配, 可以进行下一个报文的处理
|
20
|
+
# OK_NO_POP: 匹配了接收队列中的报文, 但是不需要框架自动pop掉期望报文( 注意, 你需要自行处于报文 )
|
21
|
+
# FAIL: 肯定失败时使用
|
22
|
+
# NONE: 不匹配, 让框架进行下一个报文匹配
|
23
|
+
def call(hope_pkt, recv_pkt, queue)
|
24
|
+
raise "write code here"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# 一个简单的例子
|
29
|
+
class SimpleStrategy < BasicStrategy
|
30
|
+
def call(hope_pkt, recv_pkt, queue)
|
31
|
+
if hope_pkt == recv_pkt
|
32
|
+
return OK
|
33
|
+
else
|
34
|
+
return NONE
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'logger'
|
2
|
+
module DIY
|
3
|
+
class StrategyBuilder
|
4
|
+
def initialize(queue)
|
5
|
+
@ins = []
|
6
|
+
@logger = DIY::Logger
|
7
|
+
@queue = queue
|
8
|
+
end
|
9
|
+
attr_reader :queue
|
10
|
+
|
11
|
+
def add(strategy)
|
12
|
+
@ins << strategy
|
13
|
+
end
|
14
|
+
alias << add
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def logger
|
21
|
+
@logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def recv_pkt(pkt)
|
25
|
+
recv_pkt_queue(queue,pkt)
|
26
|
+
end
|
27
|
+
|
28
|
+
def recv_pkt_queue(queue, recv_pkt)
|
29
|
+
hope_pkt = queue.peek
|
30
|
+
logger.debug("recv_pkt, I hope: #{ hope_pkt[0..10].dump rescue nil }...")
|
31
|
+
|
32
|
+
return if hope_pkt.nil?
|
33
|
+
|
34
|
+
@ins.each do |strategy|
|
35
|
+
begin
|
36
|
+
ret = strategy.call(hope_pkt, recv_pkt, queue)
|
37
|
+
rescue Exception => e
|
38
|
+
logger.error("strategy call exception: #{e.class} -> #{e.message}")
|
39
|
+
raise
|
40
|
+
#仅仅忽略
|
41
|
+
else
|
42
|
+
if ret == Strategy::OK
|
43
|
+
logger.info("pkt same:")
|
44
|
+
queue.pop
|
45
|
+
return
|
46
|
+
elsif ret == Strategy::OK_NO_POP
|
47
|
+
logger.info("pkt same but no pop:")
|
48
|
+
return
|
49
|
+
elsif ret == Strategy::FAIL
|
50
|
+
logger.warn("pkt fail:")
|
51
|
+
elsif ret == Strategy::NONE
|
52
|
+
logger.debug("pkt jumpped:")
|
53
|
+
next
|
54
|
+
end # end of if
|
55
|
+
end # end of begin
|
56
|
+
end # end of each
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/diy/utils.rb
ADDED
data/lib/diy/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
class NoMacEqualStrategy < DIY::BasicStrategy
|
2
|
+
def call(hope_pkt, recv_pkt, queue)
|
3
|
+
return OK if hope_pkt[12..-1] == recv_pkt[12..-1]
|
4
|
+
return NONE
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
nomac = NoMacEqualStrategy.new
|
9
|
+
|
10
|
+
change_mac = lambda do |pkt|
|
11
|
+
pkt[6..11] = "aaaaaa"
|
12
|
+
return pkt
|
13
|
+
end
|
14
|
+
|
15
|
+
builder = DIY::Builder.new do
|
16
|
+
use nomac
|
17
|
+
before_send &change_mac
|
18
|
+
pcapfile "pcaps/gre.pcap"
|
19
|
+
end
|
20
|
+
|
21
|
+
builder.run
|
data/spec/logger_spec.rb
ADDED
@@ -74,30 +74,4 @@ describe DIY::Queue do
|
|
74
74
|
q.delete_at(0).should == File.read( File.join( File.dirname(__FILE__), 'helper/pkt2' ) )
|
75
75
|
end
|
76
76
|
|
77
|
-
end
|
78
|
-
|
79
|
-
describe DIY::Controller do
|
80
|
-
before(:each) do
|
81
|
-
@device_name = FFI::PCap.dump_devices[0][0]
|
82
|
-
@live = FFI::PCap::Live.new(:dev=>@device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
83
|
-
@offline = FFI::PCap::Offline.new('../simple/pcaps/gre.pcap')
|
84
|
-
end
|
85
|
-
|
86
|
-
it "#run" do
|
87
|
-
q = nil
|
88
|
-
server = Thread.new do
|
89
|
-
q = DIY::Queue.new(@offline)
|
90
|
-
q.stub(:server?).and_return(true)
|
91
|
-
DIY::Queue.stub(:new).and_return(q)
|
92
|
-
s = DIY::Controller.new(@live, @offline)
|
93
|
-
s.run
|
94
|
-
end
|
95
|
-
device_name = FFI::PCap.dump_devices[0][0]
|
96
|
-
live = FFI::PCap::Live.new(:dev=>@device_name, :handler => FFI::PCap::Handler, :promisc => true)
|
97
|
-
offline = FFI::PCap::Offline.new('../simple/pcaps/gre.pcap')
|
98
|
-
c = DIY::Controller.new(live, offline)
|
99
|
-
q.wait_until { q.peek != nil }
|
100
|
-
lambda { c.run ; server.join }.should_not raise_error
|
101
|
-
end
|
102
|
-
|
103
77
|
end
|
data/spec/sender_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DIY::Sender do
|
4
|
+
|
5
|
+
class FakeLive
|
6
|
+
def inject
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "#before_send" do
|
11
|
+
live = double(FakeLive)
|
12
|
+
|
13
|
+
before_send_call = lambda { |pkt| pkt[0..2] = "111"; pkt }
|
14
|
+
pkt = "222222"
|
15
|
+
npkt = "111222"
|
16
|
+
live.should_receive(:inject).with(npkt).and_return(nil)
|
17
|
+
sender = DIY::Sender.new(live )
|
18
|
+
sender.before_send(&before_send_call)
|
19
|
+
lambda { sender.inject(pkt) }.should_not raise_error
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: DIY-pcap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- yafei Lee
|
@@ -14,8 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2012-09-
|
18
|
-
default_executable:
|
18
|
+
date: 2012-09-11 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: ffi-pcap
|
@@ -25,6 +25,7 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
+
hash: 23
|
28
29
|
segments:
|
29
30
|
- 0
|
30
31
|
- 2
|
@@ -52,11 +53,22 @@ files:
|
|
52
53
|
- bin/pcap
|
53
54
|
- bin/rpcap
|
54
55
|
- lib/DIY-pcap.rb
|
56
|
+
- lib/diy/builder.rb
|
57
|
+
- lib/diy/controller.rb
|
55
58
|
- lib/diy/dig.rb
|
59
|
+
- lib/diy/exceptions.rb
|
60
|
+
- lib/diy/logger.rb
|
56
61
|
- lib/diy/pcap.rb
|
62
|
+
- lib/diy/queue.rb
|
63
|
+
- lib/diy/recver.rb
|
64
|
+
- lib/diy/sender.rb
|
65
|
+
- lib/diy/strategy.rb
|
66
|
+
- lib/diy/strategy_builder.rb
|
57
67
|
- lib/diy/task.rb
|
68
|
+
- lib/diy/utils.rb
|
58
69
|
- lib/diy/version.rb
|
59
70
|
- simple/cmd-pcap.rb
|
71
|
+
- simple/diy-strategy-pcap.rb
|
60
72
|
- simple/pcap.rb
|
61
73
|
- simple/pcaps/gre.pcap
|
62
74
|
- simple/pcaps/r1.dat
|
@@ -66,14 +78,16 @@ files:
|
|
66
78
|
- simple/pcaps/s2.dat
|
67
79
|
- simple/pcaps/s3.dat
|
68
80
|
- simple/pcaps/s4.dat
|
69
|
-
- spec/
|
81
|
+
- spec/builder_spec.rb
|
70
82
|
- spec/helper/pkt1
|
71
83
|
- spec/helper/pkt2
|
72
84
|
- spec/helper/pkt3
|
73
85
|
- spec/helper/pkt4
|
74
86
|
- spec/helper/pkt5
|
87
|
+
- spec/logger_spec.rb
|
88
|
+
- spec/queue_spec.rb
|
89
|
+
- spec/sender_spec.rb
|
75
90
|
- spec/spec_helper.rb
|
76
|
-
has_rdoc: true
|
77
91
|
homepage: ""
|
78
92
|
licenses: []
|
79
93
|
|
@@ -87,6 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
101
|
requirements:
|
88
102
|
- - ">="
|
89
103
|
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
90
105
|
segments:
|
91
106
|
- 0
|
92
107
|
version: "0"
|
@@ -95,13 +110,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
110
|
requirements:
|
96
111
|
- - ">="
|
97
112
|
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
98
114
|
segments:
|
99
115
|
- 0
|
100
116
|
version: "0"
|
101
117
|
requirements: []
|
102
118
|
|
103
119
|
rubyforge_project:
|
104
|
-
rubygems_version: 1.
|
120
|
+
rubygems_version: 1.8.24
|
105
121
|
signing_key:
|
106
122
|
specification_version: 3
|
107
123
|
summary: DIY pcap send and recv
|