mu 5.7.23 → 5.7.24
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/mu/api/muapi.rb +98 -7
- data/lib/mu/api/scale.rb +9 -5
- data/lib/mu/command/cmd_muapi.rb +79 -2
- data/lib/mu/command/cmd_runanalysis.rb +376 -0
- data/lib/mu/helper.rb +17 -0
- data/version.rb +1 -1
- metadata +83 -90
data/lib/mu/api/muapi.rb
CHANGED
@@ -2,7 +2,7 @@ class Mu
|
|
2
2
|
class Muapi
|
3
3
|
include Helper
|
4
4
|
|
5
|
-
attr_accessor :host, :docroot, :posted_uuid, :run_uuid, :job_id, :username, :password, :params, :expected_error
|
5
|
+
attr_accessor :host, :docroot, :posted_uuid, :run_uuid, :job_id, :username, :password, :params, :expected_error, :filepath
|
6
6
|
|
7
7
|
def initialize(host=ENV['MU_IP'], username=ENV['MU_ADMIN_USER'], password=ENV['MU_ADMIN_PASS'])
|
8
8
|
@host = host
|
@@ -56,6 +56,49 @@ class Muapi
|
|
56
56
|
end
|
57
57
|
return @run_uuid
|
58
58
|
end
|
59
|
+
|
60
|
+
# starts a test from a template file
|
61
|
+
# * template = the path and name of the template file that contains a single Test template
|
62
|
+
def run_from_template(template, rename="")
|
63
|
+
response = import_templates(template)
|
64
|
+
msg response, Logger::DEBUG
|
65
|
+
doc = make_xml(response)
|
66
|
+
uuid = ""
|
67
|
+
unless doc.xpath("//uuid").empty?
|
68
|
+
node = doc.at_xpath("//uuid")
|
69
|
+
uuid = node.content()
|
70
|
+
end
|
71
|
+
msg uuid, Logger::DEBUG
|
72
|
+
req = "analysis/run?uuid=#{uuid}"
|
73
|
+
unless rename.empty?
|
74
|
+
req = "#{req}&rename=#{rename}"
|
75
|
+
end
|
76
|
+
msg req, Logger::DEBUG
|
77
|
+
doc = @http.get_xml(req)
|
78
|
+
unless doc.xpath("//analysis").empty?
|
79
|
+
@run_uuid = doc.xpath("//analysis")[0].attribute('uuid')
|
80
|
+
return @run_uuid
|
81
|
+
end
|
82
|
+
return @run_uuid
|
83
|
+
end
|
84
|
+
|
85
|
+
# import templates from a file
|
86
|
+
# * template = the path and name of the template file that contains a single Test template
|
87
|
+
def import_templates(template)
|
88
|
+
# open the file and pull the contents for posting
|
89
|
+
begin
|
90
|
+
data = File.open(template,'r') {|f| f.read }
|
91
|
+
rescue Exception => e
|
92
|
+
msg "File read error for #{template}: #{e}"
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
# post the contents of the file
|
97
|
+
response = @http.post("templates/import",whole_file)
|
98
|
+
msg response, Logger::DEBUG
|
99
|
+
|
100
|
+
return response
|
101
|
+
end
|
59
102
|
|
60
103
|
# stops a running test
|
61
104
|
# * uuid = the uuid of the test
|
@@ -104,9 +147,9 @@ class Muapi
|
|
104
147
|
# returns a list of faults from the specified test
|
105
148
|
# * uuid = the uuid of the test
|
106
149
|
def get_faults(uuid=@run_uuid)
|
107
|
-
doc = @http.get_xml("
|
150
|
+
doc = @http.get_xml("analysis/status?uuid=#{uuid}")
|
108
151
|
unless doc.xpath("//analysis").empty?
|
109
|
-
faults = @http.get_xml("analysis/getFaultList?uuid=#{uuid}"
|
152
|
+
faults = @http.get_xml("analysis/getFaultList?uuid=#{uuid}")
|
110
153
|
return faults
|
111
154
|
end
|
112
155
|
return "error: no analysis with uuid: #{uuid} found"
|
@@ -149,16 +192,64 @@ class Muapi
|
|
149
192
|
return @http.get_xml("templates/export?uuid=#{uuid}")
|
150
193
|
end
|
151
194
|
|
152
|
-
|
195
|
+
# performs archive operations
|
153
196
|
# * command=run to create a test archive
|
154
197
|
# * command=status to view the status of a test archive job
|
155
198
|
# * command=get to download a test archive job
|
156
199
|
# * uuid = the uuid of the test
|
157
|
-
|
200
|
+
# * title = string to include as title if not empty
|
201
|
+
# * notes = string to add to notes field if not empty
|
202
|
+
# * evts = boolean to include evts, default is true
|
203
|
+
# * pcaps = boolean to include pcaps, default is true
|
204
|
+
# * samples = boolean to include samples, default is false
|
205
|
+
# * logo = boolean to include logo, default is false
|
206
|
+
# * audit = boolean to include audit, default is false
|
207
|
+
# * sign = boolean to perform sign, default is false
|
208
|
+
def archive(command="run", id=@run_uuid, filepath='.', title="", notes="", evts=true, pcaps=true, samples=false, logo=false, audit=false, sign=false)
|
158
209
|
case command
|
159
210
|
when 'run'
|
160
211
|
request_string = "archive/run?uuid=#{id}"
|
161
|
-
|
212
|
+
# not sure where the hell whis is set so I'm commenting out and running my way
|
213
|
+
#request_string += @params unless @params.nil?
|
214
|
+
# need to set title is not empty
|
215
|
+
if title != "" and title != nil
|
216
|
+
# replace all spaces with %20 and add
|
217
|
+
request_string += "&title=" + URI.encode(title)
|
218
|
+
end
|
219
|
+
# need to set notes if not empty
|
220
|
+
if notes != "" and notes != nil
|
221
|
+
# replace all spaces with %20 and add
|
222
|
+
request_string += "¬es=" + URI.encode(notes)
|
223
|
+
end
|
224
|
+
tmpS = ""
|
225
|
+
# do we need to add evts
|
226
|
+
if evts
|
227
|
+
tmpS += "evts,"
|
228
|
+
end
|
229
|
+
# do we need need to add pcaps
|
230
|
+
if pcaps
|
231
|
+
tmpS += "pcaps,"
|
232
|
+
end
|
233
|
+
# do we need need to add sample pcaps
|
234
|
+
if samples
|
235
|
+
tmpS += "samples,"
|
236
|
+
end
|
237
|
+
# do we need need to add logo
|
238
|
+
if logo
|
239
|
+
tmpS += "logo,"
|
240
|
+
end
|
241
|
+
# do we need need to add audit
|
242
|
+
if audit
|
243
|
+
tmpS += "audit"
|
244
|
+
end
|
245
|
+
if tmpS != ""
|
246
|
+
request_string += "&include="+tmpS
|
247
|
+
end
|
248
|
+
# do we need need to sign
|
249
|
+
if sign
|
250
|
+
request_string += "&sign"
|
251
|
+
end
|
252
|
+
msg request_string, Logger::DEBUG
|
162
253
|
doc = @http.get_xml(request_string)
|
163
254
|
unless doc.xpath("//job").empty?
|
164
255
|
@job_id = doc.xpath("//job")[0].attribute('id')
|
@@ -178,7 +269,7 @@ class Muapi
|
|
178
269
|
end
|
179
270
|
return false
|
180
271
|
end
|
181
|
-
|
272
|
+
|
182
273
|
# performs backup operations
|
183
274
|
# * command=run to create a system backup file.
|
184
275
|
# * command=status to view the status of a backup job. If no backup job is running, gets the date of the most recent backup.
|
data/lib/mu/api/scale.rb
CHANGED
@@ -55,11 +55,15 @@ class Scale
|
|
55
55
|
# * param = the parameter to configure (e.g. volume)
|
56
56
|
# * value = the parameter's value ( e.g. 100)
|
57
57
|
def configure(param, value)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
begin
|
59
|
+
if param == "pattern" and value.is_a?(String)
|
60
|
+
value = JSON.parse(value)
|
61
|
+
end
|
62
|
+
@configuration[param] = value
|
63
|
+
File.open(@config_file,'w'){|f| f.write(JSON.pretty_generate(@configuration))}
|
64
|
+
rescue => e
|
65
|
+
raise "Something is wrong with the JSON parsing or generation:#{e} backtrace:#{e.backtrace}"
|
66
|
+
end
|
63
67
|
end
|
64
68
|
|
65
69
|
# starts a scale test with the class @configuration object
|
data/lib/mu/command/cmd_muapi.rb
CHANGED
@@ -53,6 +53,33 @@ class Cmd_muapi < Command
|
|
53
53
|
msg response
|
54
54
|
return response
|
55
55
|
end
|
56
|
+
|
57
|
+
# runs an analysis, reference is the posted uuid
|
58
|
+
# ex: cmd_run_template("/path/my_template_file.xml", "my_new_name_for_test")
|
59
|
+
# * argv = command-line arguments, requires a template file (-f) and an optional name such that each successive run of the same uuid yields a new name
|
60
|
+
def cmd_run_template argv
|
61
|
+
setup argv
|
62
|
+
filepath = @hash['filepath']
|
63
|
+
if @hash['boolean'].nil?
|
64
|
+
rename = ""
|
65
|
+
else
|
66
|
+
rename = @hash['boolean']
|
67
|
+
end
|
68
|
+
response = @api.run_from_template(filepath, rename)
|
69
|
+
msg response
|
70
|
+
return response
|
71
|
+
end
|
72
|
+
|
73
|
+
# imports xml templates,
|
74
|
+
# ex: import_templates("/path/my_template_file.xml")
|
75
|
+
# * argv = command-line arguments, requires a template file (-f)
|
76
|
+
def cmd_import_templates argv
|
77
|
+
setup argv
|
78
|
+
template_file = @hash['filepath']
|
79
|
+
response = @api.import_templates(template_file)
|
80
|
+
msg response
|
81
|
+
return response
|
82
|
+
end
|
56
83
|
|
57
84
|
# aborts a running analysis. the next queued analysis will start
|
58
85
|
# * argv = command-line arguments, requires a uuid (-u) argument specifying the test
|
@@ -178,7 +205,43 @@ class Cmd_muapi < Command
|
|
178
205
|
setup argv
|
179
206
|
command = @hash['command']
|
180
207
|
job_id = @hash['uuid']
|
181
|
-
|
208
|
+
includes = @hash['include']
|
209
|
+
filepath = @hash['filepath']
|
210
|
+
if filepath==nil
|
211
|
+
filepath = "."
|
212
|
+
end
|
213
|
+
notes,title=""
|
214
|
+
pcaps,evts = true
|
215
|
+
sign,logo,samples,audit = false
|
216
|
+
if includes!=nil
|
217
|
+
pcaps,evts = false
|
218
|
+
includes.split(",").each do | option |
|
219
|
+
if option=="pcaps"
|
220
|
+
pcaps=true
|
221
|
+
elsif option=="evts"
|
222
|
+
evts = true
|
223
|
+
elsif option=="sign"
|
224
|
+
sign = true
|
225
|
+
elsif option=="logo"
|
226
|
+
logo = true
|
227
|
+
elsif option=="samples"
|
228
|
+
samples = true
|
229
|
+
elsif option=="audit"
|
230
|
+
audit = true
|
231
|
+
elsif option.match(/^notes=/)
|
232
|
+
matches = option.match(/^notes=(.+)/)
|
233
|
+
if matches!=nil
|
234
|
+
notes = matches[1]
|
235
|
+
end
|
236
|
+
elsif option.match(/^title=/)
|
237
|
+
matches = option.match(/^title=(.+)/)
|
238
|
+
if matches!=nil
|
239
|
+
title = matches[1]
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
response = @api.archive(command, job_id, filepath, title, notes, evts, pcaps, samples, logo, audit, sign)
|
182
245
|
msg response
|
183
246
|
return response
|
184
247
|
end
|
@@ -254,6 +317,11 @@ private
|
|
254
317
|
help
|
255
318
|
exit
|
256
319
|
end
|
320
|
+
|
321
|
+
if [ '-i', '--include' ].member? k
|
322
|
+
@hash['include'] = shift(k, argv)
|
323
|
+
next
|
324
|
+
end
|
257
325
|
|
258
326
|
if [ '-m', '--mu_string' ].member? k
|
259
327
|
mu_string = shift(k, argv)
|
@@ -294,6 +362,11 @@ private
|
|
294
362
|
@hash['uuid'] = shift(k, argv)
|
295
363
|
next
|
296
364
|
end
|
365
|
+
|
366
|
+
if [ '-f', '--filepath' ].member? k
|
367
|
+
@hash['filepath'] = shift(k, argv)
|
368
|
+
next
|
369
|
+
end
|
297
370
|
|
298
371
|
if [ '-v', '--verbose' ].member? k
|
299
372
|
$log.level = Logger::DEBUG
|
@@ -308,7 +381,9 @@ private
|
|
308
381
|
helps = [
|
309
382
|
{ :short => '-b', :long => '--boolean', :value => '<string>', :help => 'boolean arg' },
|
310
383
|
{ :short => '-c', :long => '--command', :value => '<string>', :help => 'e.g. run|get|status' },
|
384
|
+
{ :short => '-f', :long => '--filepath', :value => '', :help => 'the template file to run' },
|
311
385
|
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
386
|
+
{ :short => '-i', :long => '--include', :value => '<string>', :help => 'comma separated list of options to include' },
|
312
387
|
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
313
388
|
{ :short => '-n', :long => '--name', :value => '<string>', :help => 'name for filtering' },
|
314
389
|
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
@@ -320,7 +395,7 @@ private
|
|
320
395
|
]
|
321
396
|
|
322
397
|
cmds = [
|
323
|
-
"mu cmd_muapi:archive -c <command> -u <uuid>",
|
398
|
+
"mu cmd_muapi:archive -c <command> -u <uuid> -i <notes=\"my notes\",title=\"my title\",pcaps,evts,samples,audit,logo,sign>",
|
324
399
|
"mu cmd_muapi:backup -c <command> [-n <name>]",
|
325
400
|
"mu cmd_muapi:capture -c <command> -p <port> [-u <uuid>]",
|
326
401
|
"mu cmd_muapi:delete -u <uuid>",
|
@@ -329,11 +404,13 @@ private
|
|
329
404
|
"mu cmd_muapi:get_faults -u <uuid>",
|
330
405
|
"mu cmd_muapi:get_name -u <uuid>",
|
331
406
|
"mu cmd_muapi:help",
|
407
|
+
"mu cmd_muapi:import_templates -f <my_template_file>",
|
332
408
|
"mu cmd_muapi:list -t <type>",
|
333
409
|
"mu cmd_muapi:list_by_status -s <status>",
|
334
410
|
"mu cmd_muapi:pause -u <uuid>",
|
335
411
|
"mu cmd_muapi:resume -u <uuid>",
|
336
412
|
"mu cmd_muapi:run -u <uuid> [-b rename]",
|
413
|
+
"mu cmd_muapi:run_template -f <filepath> [-b rename]",
|
337
414
|
"mu cmd_muapi:status -u <uuid>",
|
338
415
|
"mu cmd_muapi:stop -u <uuid>",
|
339
416
|
"mu cmd_muapi:types",
|
@@ -0,0 +1,376 @@
|
|
1
|
+
# Use these commands to access the legacy REST API for Test Runs (Protocol Mutation, Scenario Mutation).
|
2
|
+
|
3
|
+
require 'mu/api/muapi'
|
4
|
+
class Mu
|
5
|
+
class Command
|
6
|
+
class Cmd_runfuzz < Command
|
7
|
+
|
8
|
+
attr_accessor :host, :username, :password, :api, :docroot
|
9
|
+
|
10
|
+
# displays command-line help
|
11
|
+
# * argv = command-line arguments
|
12
|
+
def cmd_help argv
|
13
|
+
help
|
14
|
+
end
|
15
|
+
|
16
|
+
# capture has a set of three commands that are used to generate
|
17
|
+
# packet captures, poll the status and return the resulting file
|
18
|
+
# ex:
|
19
|
+
# * argv = command-line arguments, requires a command (-c) argument
|
20
|
+
# * command=run returns the job_id
|
21
|
+
# * command=status (called after 'run'), requires the job_id (-u) argument
|
22
|
+
# * command=get (called when status returns "Finished"), requires the job_id (-u) argument
|
23
|
+
# * port = the Mu interface on which to capture packets
|
24
|
+
def cmd_run argv
|
25
|
+
setup argv
|
26
|
+
# set all aparms
|
27
|
+
archive = @hash['archive']
|
28
|
+
directory = @hash['directory']
|
29
|
+
force = @hash['force']
|
30
|
+
interval = @hash['interval']
|
31
|
+
output = @hash['output']
|
32
|
+
prepend = @hash['prepend']
|
33
|
+
template = @hash['template']
|
34
|
+
uuid = @hash['uuid']
|
35
|
+
|
36
|
+
# set any timers to minimum non psychotic numbers
|
37
|
+
sleeptime = 10 # 10 sec
|
38
|
+
if force != nil
|
39
|
+
force = Integer(force)
|
40
|
+
if force < 1
|
41
|
+
force = 1
|
42
|
+
end
|
43
|
+
else
|
44
|
+
force = 0
|
45
|
+
end
|
46
|
+
if interval != nil
|
47
|
+
interval = Integer(interval)
|
48
|
+
if interval < 5
|
49
|
+
interval = 5
|
50
|
+
end
|
51
|
+
if interval < sleeptime
|
52
|
+
sleeptime = interval
|
53
|
+
end
|
54
|
+
else
|
55
|
+
interval = 0
|
56
|
+
end
|
57
|
+
|
58
|
+
# my_uuid_hash is a hash that will contain the name, and uuid of the test to run my_name => my_uuid
|
59
|
+
my_uuid_hash = {}
|
60
|
+
|
61
|
+
# determine proper execution path: uuid, template, or directory
|
62
|
+
if directory != nil
|
63
|
+
# load all xml files in directory and add uuids to execution list
|
64
|
+
files = Dir.glob(File.join(@hash["directory"],"","*.xml"))
|
65
|
+
files.each do | file |
|
66
|
+
response = @api.import_templates(file)
|
67
|
+
msg response, Logger::DEBUG
|
68
|
+
doc = make_xml(response)
|
69
|
+
unless doc.xpath("//model_object").empty?
|
70
|
+
doc.xpath("//model_object").each do |node|
|
71
|
+
my_uuid = node.xpath("uuid").text
|
72
|
+
my_name = node.xpath("name").text
|
73
|
+
my_type = node.xpath("type").text
|
74
|
+
if my_type=="Analysis"
|
75
|
+
msg "type = #{my_type} uuid = #{my_uuid} name = #{my_name}", Logger::DEBUG
|
76
|
+
my_uuid_hash[my_uuid] = my_name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
if template != nil
|
83
|
+
# import template file into mu and add all uuids to list
|
84
|
+
response = @api.import_templates(template)
|
85
|
+
msg response, Logger::DEBUG
|
86
|
+
doc = make_xml(response)
|
87
|
+
unless doc.xpath("//model_object").empty?
|
88
|
+
doc.xpath("//model_object").each do |node|
|
89
|
+
my_uuid = node.xpath("uuid").text
|
90
|
+
my_name = node.xpath("name").text
|
91
|
+
my_type = node.xpath("type").text
|
92
|
+
if my_type=="Analysis"
|
93
|
+
msg "type = #{my_type} uuid = #{my_uuid} name = #{my_name}", Logger::DEBUG
|
94
|
+
my_uuid_hash[my_uuid] = my_name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
if uuid != nil
|
100
|
+
# add all uuids to list
|
101
|
+
if uuid =~ /,/
|
102
|
+
list = uuid.split(",")
|
103
|
+
list.each do | my_uuid |
|
104
|
+
response = @api.get_name(my_uuid)
|
105
|
+
my_uuid_hash[my_uuid] = response
|
106
|
+
end
|
107
|
+
else
|
108
|
+
# add single uuid to list
|
109
|
+
response = @api.get_name(uuid)
|
110
|
+
my_uuid_hash[uuid] = response
|
111
|
+
end
|
112
|
+
end
|
113
|
+
if my_uuid_hash.empty?
|
114
|
+
msg "no valid test option selected, please specify directory, template file, or uuid"
|
115
|
+
help
|
116
|
+
exit
|
117
|
+
end
|
118
|
+
|
119
|
+
# now we run all the tests
|
120
|
+
#msg "RUNNING"
|
121
|
+
results = {}
|
122
|
+
map = my_uuid_hash.each_pair do |key,value|
|
123
|
+
t1 = Time.now.localtime.tv_sec
|
124
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
125
|
+
suspend_time = t1
|
126
|
+
polling_time = t1
|
127
|
+
if prepend != nil
|
128
|
+
name = "#{prepend} #{value}"
|
129
|
+
else
|
130
|
+
name = value
|
131
|
+
end
|
132
|
+
msg "my name = #{name} with uuid = #{key}"
|
133
|
+
run = true
|
134
|
+
run_uuid = @api.run(key, URI.encode(name))
|
135
|
+
while run
|
136
|
+
sleep(sleeptime)
|
137
|
+
status = @api.status(run_uuid)
|
138
|
+
msg status
|
139
|
+
t2 = Time.now.localtime.tv_sec
|
140
|
+
msg t2-t1
|
141
|
+
if interval > 0
|
142
|
+
if t2-polling_time > interval
|
143
|
+
faults = @api.get_faults(run_uuid)
|
144
|
+
msg faults, Logger::DEBUG
|
145
|
+
# faults should be an xml doc already
|
146
|
+
unless faults.xpath("//fault_list_summary").empty?
|
147
|
+
count = 0
|
148
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
149
|
+
faults.xpath("//tba_fault").each do | node |
|
150
|
+
count += 1
|
151
|
+
confidence_level = node.xpath("confidence_level").text
|
152
|
+
title = node.xpath("title").text
|
153
|
+
fault_detection = node.xpath("fault_detection").text
|
154
|
+
fault_isolation = node.xpath("fault_isolation").text
|
155
|
+
attack_type = node.xpath("attack_type").text
|
156
|
+
if confidence_level =~ /5/
|
157
|
+
confidence_level_5 += 1
|
158
|
+
elsif confidence_level =~ /4/
|
159
|
+
confidence_level_4 += 1
|
160
|
+
elsif confidence_level =~ /3/
|
161
|
+
confidence_level_3 += 1
|
162
|
+
elsif confidence_level =~ /2/
|
163
|
+
confidence_level_2 += 1
|
164
|
+
elsif confidence_level =~ /1/
|
165
|
+
confidence_level_1 += 1
|
166
|
+
end
|
167
|
+
end
|
168
|
+
msg "Current fault count: #{count}, confidence_level 5: #{confidence_level_5}"+
|
169
|
+
", confidence_level 4: #{confidence_level_4}, confidence_level 3: #{confidence_level_3}"+
|
170
|
+
", confidence_level 2: #{confidence_level_2}, confidence_level 1: #{confidence_level_1}"
|
171
|
+
end
|
172
|
+
polling_time = Time.now.localtime.tv_sec
|
173
|
+
end
|
174
|
+
end
|
175
|
+
if status =~ /ABORTED/ or status =~ /FINISHED/ or status =~ /FAILED/
|
176
|
+
run = false
|
177
|
+
elsif status =~ /SUSPENDED/
|
178
|
+
msg "SUSPEND--->"
|
179
|
+
if t2-suspend_time > force*60
|
180
|
+
response = @api.resume(run_uuid)
|
181
|
+
msg response
|
182
|
+
suspend_time = Time.now.localtime.tv_sec
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# now we pull results for run and tabulate fault list
|
187
|
+
job_id = @api.archive("run",run_uuid,"",name,"Run via Mu Ruby Gem API #{Time.now}",true,true,true,false,false,false)
|
188
|
+
job = true
|
189
|
+
count = 0
|
190
|
+
while job
|
191
|
+
job_status = @api.archive("status", job_id)
|
192
|
+
msg "job_status = #{job_status}"
|
193
|
+
if job_status =~ /Finished/
|
194
|
+
job = false
|
195
|
+
end
|
196
|
+
sleep(sleeptime)
|
197
|
+
count += 1
|
198
|
+
if count > 30
|
199
|
+
job = false
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if Dir[name] == nil
|
203
|
+
Dir.mkdir(name)
|
204
|
+
end
|
205
|
+
response = @api.archive("get",job_id,name)
|
206
|
+
faults = @api.get_faults(run_uuid)
|
207
|
+
msg faults, Logger::DEBUG
|
208
|
+
# faults should be an xml doc already
|
209
|
+
unless faults.xpath("//fault_list_summary").empty?
|
210
|
+
count = 0
|
211
|
+
confidence_level_5,confidence_level_4,confidence_level_3,confidence_level_2,confidence_level_1 = 0, 0, 0, 0, 0
|
212
|
+
faults.xpath("//tba_fault").each do | node |
|
213
|
+
count += 1
|
214
|
+
confidence_level = node.xpath("confidence_level").text
|
215
|
+
title = node.xpath("title").text
|
216
|
+
fault_detection = node.xpath("fault_detection").text
|
217
|
+
fault_isolation = node.xpath("fault_isolation").text
|
218
|
+
attack_type = node.xpath("attack_type").text
|
219
|
+
if confidence_level =~ /5/
|
220
|
+
confidence_level_5 += 1
|
221
|
+
elsif confidence_level =~ /4/
|
222
|
+
confidence_level_4 += 1
|
223
|
+
elsif confidence_level =~ /3/
|
224
|
+
confidence_level_3 += 1
|
225
|
+
elsif confidence_level =~ /2/
|
226
|
+
confidence_level_2 += 1
|
227
|
+
elsif confidence_level =~ /1/
|
228
|
+
confidence_level_1 += 1
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
msg "Ending fault countfor #{name}: #{count}, confidence_level 5: #{confidence_level_5}"+
|
233
|
+
", confidence_level 4: #{confidence_level_4}, confidence_level 3: #{confidence_level_3}"+
|
234
|
+
", confidence_level 2: #{confidence_level_2}, confidence_level 1: #{confidence_level_1}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
#response = @api.capture(command, port, job_id)
|
238
|
+
|
239
|
+
return "RUN"
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
|
245
|
+
def setup argv
|
246
|
+
parse_cli argv
|
247
|
+
@host = (@@mu_ip.nil?) ? "127.0.0.1" : @@mu_ip
|
248
|
+
@username = (@@mu_admin_user.nil?) ? "admin" : @@mu_admin_user
|
249
|
+
@password = (@@mu_admin_pass.nil?) ? "admin" : @@mu_admin_pass
|
250
|
+
@docroot = "/api/v3"
|
251
|
+
@params = nil
|
252
|
+
@expected_error = nil
|
253
|
+
@api = Muapi.new(@host, @username, @password)
|
254
|
+
msg "Created API object to :#{@host}", Logger::DEBUG
|
255
|
+
end
|
256
|
+
|
257
|
+
def parse_cli argv
|
258
|
+
args = Array.new
|
259
|
+
@hash = Hash.new
|
260
|
+
while not argv.empty?
|
261
|
+
args << argv.shift if argv.first[0,1] != '-'
|
262
|
+
|
263
|
+
k = argv.shift
|
264
|
+
|
265
|
+
if [ '-a', '--archive' ].member? k
|
266
|
+
@hash['archive'] = shift(k, argv)
|
267
|
+
next
|
268
|
+
end
|
269
|
+
|
270
|
+
if [ '-d', '--dir' ].member? k
|
271
|
+
@hash['directory'] = shift(k, argv)
|
272
|
+
next
|
273
|
+
end
|
274
|
+
|
275
|
+
if [ '-f', '--force' ].member? k
|
276
|
+
@hash['force'] = shift(k, argv)
|
277
|
+
next
|
278
|
+
end
|
279
|
+
|
280
|
+
if [ '-h', '--help' ].member? k
|
281
|
+
help
|
282
|
+
exit
|
283
|
+
end
|
284
|
+
|
285
|
+
if [ '-i', '--interval' ].member? k
|
286
|
+
@hash['interval'] = shift(k, argv)
|
287
|
+
next
|
288
|
+
end
|
289
|
+
|
290
|
+
if [ '-m', '--mu_string' ].member? k
|
291
|
+
mu_string = shift(k, argv)
|
292
|
+
if mu_string =~ /(.+?):(.+?)@(.*)/
|
293
|
+
@@mu_admin_user = $1
|
294
|
+
@@mu_admin_pass = $2
|
295
|
+
@@mu_ip = $3
|
296
|
+
end
|
297
|
+
next
|
298
|
+
end
|
299
|
+
|
300
|
+
if [ '-n', '--name' ].member? k
|
301
|
+
@hash['name'] = shift(k, argv)
|
302
|
+
next
|
303
|
+
end
|
304
|
+
|
305
|
+
if [ '-o', '--output' ].member? k
|
306
|
+
$stdout.reopen(shift(k, argv), "w")
|
307
|
+
next
|
308
|
+
end
|
309
|
+
|
310
|
+
if [ '-p', '--prepend' ].member? k
|
311
|
+
@hash['prepend'] = shift(k, argv)
|
312
|
+
next
|
313
|
+
end
|
314
|
+
|
315
|
+
if [ '-t', '--template' ].member? k
|
316
|
+
@hash['template'] = shift(k, argv)
|
317
|
+
next
|
318
|
+
end
|
319
|
+
|
320
|
+
if [ '-u', '--uuid' ].member? k
|
321
|
+
@hash['uuid'] = shift(k, argv)
|
322
|
+
next
|
323
|
+
end
|
324
|
+
|
325
|
+
if [ '-v', '--verbose' ].member? k
|
326
|
+
$log.level = Logger::DEBUG
|
327
|
+
next
|
328
|
+
end
|
329
|
+
msg "Unknown argument #{k}"
|
330
|
+
help
|
331
|
+
exit
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
args
|
336
|
+
end
|
337
|
+
|
338
|
+
def help
|
339
|
+
helps = [
|
340
|
+
{ :short => '-a', :long => '--archive', :value => '<string>', :help => 'collect all archive result files with comma separated options list, pcaps and evts on by default' },
|
341
|
+
{ :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing the scenario files' },
|
342
|
+
{ :short => '-f', :long => '--force', :value => '<integer>', :help => 'force resume on pause after time elapse in min' },
|
343
|
+
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
344
|
+
{ :short => '-i', :long => '--interval', :value => '<integer>', :help => 'execute fault status update at intervalin seconds. minimum = 5' },
|
345
|
+
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
346
|
+
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
347
|
+
{ :short => '-p', :long => '--prepend', :value => '<string>', :help => 'prepend test name with <string>' },
|
348
|
+
{ :short => '-t', :long => '--template', :value => '', :help => 'the template file to run' },
|
349
|
+
{ :short => '-u', :long => '--uuid', :value => '<string>', :help => 'comma seperated uuid list of template uuids' },
|
350
|
+
{ :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
|
351
|
+
]
|
352
|
+
|
353
|
+
cmds = [
|
354
|
+
"mu cmd_runfuzz:run -f <string /path/my-template-name.xml> -p <string> -a <string pcaps,evts,samples,logo,audit,sign ",
|
355
|
+
]
|
356
|
+
|
357
|
+
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
358
|
+
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
359
|
+
puts
|
360
|
+
puts "Usage: mu cmd_runfuzz <options>"
|
361
|
+
puts
|
362
|
+
helps.each do |h|
|
363
|
+
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
364
|
+
end
|
365
|
+
puts
|
366
|
+
puts "Available Commands"
|
367
|
+
puts
|
368
|
+
cmds.each do | c |
|
369
|
+
puts c
|
370
|
+
end
|
371
|
+
puts
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
end # Command
|
376
|
+
end # Mu
|
data/lib/mu/helper.rb
CHANGED
@@ -51,5 +51,22 @@ module Helper
|
|
51
51
|
return arr
|
52
52
|
end
|
53
53
|
|
54
|
+
def make_xml(resp)
|
55
|
+
begin
|
56
|
+
if (/<.+>/).match(resp)
|
57
|
+
xmldoc = Nokogiri::XML(resp)
|
58
|
+
else
|
59
|
+
err_node = Nokogiri::XML::Node.new('err_node', xmldoc)
|
60
|
+
err_node.content = resp
|
61
|
+
xmldoc.root << err_node
|
62
|
+
end
|
63
|
+
rescue => e
|
64
|
+
msg "Error parsing XML " + e.to_s, Logger::DEBUG
|
65
|
+
ensure
|
66
|
+
msg xmldoc, Logger::DEBUG
|
67
|
+
return xmldoc
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
54
71
|
end
|
55
72
|
end # Mu
|
data/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION='5.7.
|
1
|
+
VERSION='5.7.24'
|
metadata
CHANGED
@@ -1,125 +1,122 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: mu
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 5.7.24
|
4
5
|
prerelease:
|
5
|
-
version: 5.7.23
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- MuEng
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2011-05-13 00:00:00 -07:00
|
12
|
+
date: 2011-05-16 00:00:00.000000000 -07:00
|
14
13
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: nokogiri
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &21267240 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
22
|
-
- -
|
23
|
-
- !ruby/object:Gem::Version
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 1.4.4
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rest-client
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: *21267240
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rest-client
|
28
|
+
requirement: &21266780 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
35
33
|
version: 1.6.1
|
36
34
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: mime-types
|
40
35
|
prerelease: false
|
41
|
-
|
36
|
+
version_requirements: *21266780
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mime-types
|
39
|
+
requirement: &21266320 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version:
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '1.16'
|
47
45
|
type: :runtime
|
48
|
-
version_requirements: *id003
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: json
|
51
46
|
prerelease: false
|
52
|
-
|
47
|
+
version_requirements: *21266320
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: json
|
50
|
+
requirement: &21265940 !ruby/object:Gem::Requirement
|
53
51
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version:
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
58
56
|
type: :runtime
|
59
|
-
version_requirements: *id004
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: hexy
|
62
57
|
prerelease: false
|
63
|
-
|
58
|
+
version_requirements: *21265940
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: hexy
|
61
|
+
requirement: &21295160 !ruby/object:Gem::Requirement
|
64
62
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
68
66
|
version: 0.1.1
|
69
67
|
type: :runtime
|
70
|
-
version_requirements: *id005
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: uuid
|
73
68
|
prerelease: false
|
74
|
-
|
69
|
+
version_requirements: *21295160
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: uuid
|
72
|
+
requirement: &21294660 !ruby/object:Gem::Requirement
|
75
73
|
none: false
|
76
|
-
requirements:
|
77
|
-
- -
|
78
|
-
- !ruby/object:Gem::Version
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
79
77
|
version: 2.0.2
|
80
78
|
type: :runtime
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
email:
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *21294660
|
81
|
+
description: ! "The Mu gem allows users to include mu libraries within scripts\n that
|
82
|
+
interact with mu appliance software. The gem also supplies command line interfaces\n
|
83
|
+
\ to many of these same libraries"
|
84
|
+
email:
|
87
85
|
- info@mudynamics.com
|
88
|
-
executables:
|
86
|
+
executables:
|
89
87
|
- mu
|
90
88
|
extensions: []
|
91
|
-
|
92
89
|
extra_rdoc_files: []
|
93
|
-
|
94
|
-
|
95
|
-
- lib/mu/
|
96
|
-
- lib/mu/
|
97
|
-
- lib/mu/
|
90
|
+
files:
|
91
|
+
- lib/mu.rb
|
92
|
+
- lib/mu/har.rb
|
93
|
+
- lib/mu/http_helper.rb
|
94
|
+
- lib/mu/client.rb
|
98
95
|
- lib/mu/api/netconfig.rb
|
99
|
-
- lib/mu/api/
|
96
|
+
- lib/mu/api/muapi.rb
|
97
|
+
- lib/mu/api/homepage.rb
|
100
98
|
- lib/mu/api/system.rb
|
101
|
-
- lib/mu/
|
99
|
+
- lib/mu/api/scale.rb
|
100
|
+
- lib/mu/api/ddt.rb
|
101
|
+
- lib/mu/helper.rb
|
102
|
+
- lib/mu/maker.rb
|
103
|
+
- lib/mu/command/cmd_homepage.rb
|
102
104
|
- lib/mu/command/api.rb
|
103
105
|
- lib/mu/command/cmd_ddt.rb
|
104
|
-
- lib/mu/command/
|
106
|
+
- lib/mu/command/cmd_scale.rb
|
107
|
+
- lib/mu/command/curl.rb
|
105
108
|
- lib/mu/command/cmd_muapi.rb
|
109
|
+
- lib/mu/command/help.rb
|
106
110
|
- lib/mu/command/cmd_musl.rb
|
107
|
-
- lib/mu/command/
|
111
|
+
- lib/mu/command/cmd_system.rb
|
108
112
|
- lib/mu/command/cmd_runscale.rb
|
109
113
|
- lib/mu/command/cmd_runscenario.rb
|
114
|
+
- lib/mu/command/cmd_runanalysis.rb
|
115
|
+
- lib/mu/command/cmd_netconfig.rb
|
110
116
|
- lib/mu/command/cmd_runverify.rb
|
111
|
-
- lib/mu/command/cmd_scale.rb
|
112
|
-
- lib/mu/command/cmd_system.rb
|
113
|
-
- lib/mu/command/curl.rb
|
114
|
-
- lib/mu/command/help.rb
|
115
117
|
- lib/mu/command.rb
|
116
118
|
- lib/mu/curl/error.rb
|
117
119
|
- lib/mu/curl/verify.rb
|
118
|
-
- lib/mu/har.rb
|
119
|
-
- lib/mu/helper.rb
|
120
|
-
- lib/mu/http_helper.rb
|
121
|
-
- lib/mu/maker.rb
|
122
|
-
- lib/mu.rb
|
123
120
|
- bin/mu
|
124
121
|
- Mu_Gem.html
|
125
122
|
- version.rb
|
@@ -128,30 +125,26 @@ files:
|
|
128
125
|
has_rdoc: true
|
129
126
|
homepage: http://www.mudynamics.com
|
130
127
|
licenses: []
|
131
|
-
|
132
128
|
post_install_message:
|
133
129
|
rdoc_options: []
|
134
|
-
|
135
|
-
require_paths:
|
130
|
+
require_paths:
|
136
131
|
- lib
|
137
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
133
|
none: false
|
139
|
-
requirements:
|
140
|
-
- -
|
141
|
-
- !ruby/object:Gem::Version
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
142
137
|
version: 1.8.7
|
143
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
139
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version:
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
149
144
|
requirements: []
|
150
|
-
|
151
145
|
rubyforge_project:
|
152
146
|
rubygems_version: 1.6.2
|
153
147
|
signing_key:
|
154
148
|
specification_version: 3
|
155
149
|
summary: Mu Dynamics General Purpose Library and Command Line Tool
|
156
150
|
test_files: []
|
157
|
-
|