nexpose_scan_manager 0.0.1

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.
Files changed (2) hide show
  1. data/lib/scan_manager.rb +165 -0
  2. metadata +69 -0
@@ -0,0 +1,165 @@
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+ require 'thread'
4
+ require 'observer'
5
+ require 'nexpose'
6
+
7
+ #------------------------------------------------------------------------------------------------------
8
+ # Used to start site device scans where a user is able to specify the maximum amount of scans that
9
+ # should be running at a time. This class does not guarantee that there will be no more than the
10
+ # maximum amount of scans specified will be running BUT scans will not be started from this class
11
+ # until the current amount of scans running is less than or equal to the maximum.
12
+ #
13
+ # This class is also used to
14
+ #------------------------------------------------------------------------------------------------------
15
+ class ScanManager
16
+ include Observable
17
+
18
+ # Used to determine if the poller thread is running
19
+ attr_accessor :is_poller_thread_running
20
+
21
+ # Determines how often the poller thread is executed
22
+ attr_reader :period
23
+
24
+ # Synchronize calls that modify open data structs
25
+ @semaphore = nil
26
+
27
+ # The NeXpose API object.
28
+ @nexpose_conn = nil
29
+
30
+ # A Hash of scan-ids to an array of operations for that scan
31
+ # All tasks associated with a scan id must implement #scan_update
32
+ @conditional_device_scans = nil
33
+ @excution_cycle_started = nil
34
+ @poler_exit_on_completion = nil
35
+
36
+ private
37
+ def start_poller
38
+ @is_poller_thread_running = true
39
+ operation = proc {
40
+ puts "Scan Manager poller thread executing ..."
41
+ while true do
42
+ sleep @period.to_i
43
+ check_and_execute_op
44
+ if @execution_cycle_started and @conditional_device_scans.empty? and @scan_listeners.empty? and @poler_exit_on_completion
45
+ break
46
+ end
47
+ end
48
+
49
+ @is_poller_thread_running = false
50
+ puts "Poller exiting ..."
51
+ }
52
+
53
+ EM.defer operation
54
+ end
55
+
56
+ def check_and_execute_op
57
+ @semaphore.synchronize do
58
+
59
+ @scans_observed.each do |scan_id|
60
+ status = @nexpose_conn.scan_status scan_id
61
+ scan_stats = @nexpose_conn.scan_statistics scan_id
62
+ message = scan_stats[:message]
63
+
64
+
65
+ content = {
66
+ :scan_id => scan_id,
67
+ :status => status,
68
+ :message => message
69
+ }
70
+
71
+ changed
72
+ notify_observers content, self
73
+ end
74
+
75
+ # We start scans one per thread execution loop.
76
+ # Then we start the scan if conditions are met.
77
+ # NOTE: the only condition implemented here is the maximum amount of scans.
78
+ if @conditional_device_scans.length > 0
79
+ scan_count = 0
80
+ stats = @nexpose_conn.scan_activity
81
+
82
+ # Get a count of all the running scans
83
+ stats.each do |stat|
84
+ if (stat[:status].eql?('running') or stat[:status].eql?('dispatched'))
85
+ scan_count = scan_count + 1
86
+ end
87
+ end
88
+
89
+ for i in 0..(@conditional_device_scans.length-1)
90
+ scan_condition = @conditional_device_scans[i]
91
+ if scan_condition[:max_scans] > scan_count
92
+ res = @nexpose_conn.site_device_scan_start scan_condition[:site_id], scan_condition[:devices], scan_condition[:hosts]
93
+ if res
94
+ puts "Scan started scan ID: #{res[:scan_id]}, on engine ID: #{res[:engine_id]}"
95
+ @conditional_device_scans.delete_at i
96
+ else
97
+ put "Scan start failed for site #{site}"
98
+ end
99
+
100
+ break # Only one scan per loop can be started
101
+ end
102
+ end
103
+ end
104
+ end # End of synchronize block
105
+ end
106
+
107
+ public
108
+
109
+ #------------------------------------------------------------------------------------------------------
110
+ # The poller thread used within this class is initialized here.
111
+ #
112
+ # nexpose_conn: The NeXpose API object
113
+ # poler_exit_on_completion: 'true', if the poller thread should exit when
114
+ # when there is nothing left to process.
115
+ # period: The frequency at which the poller thread executes
116
+ #------------------------------------------------------------------------------------------------------
117
+ def initialize nexpose_conn, poler_exit_on_completion, period
118
+ @nexpose_conn = nexpose_conn
119
+ @period = period
120
+ @poler_exit_on_completion = poler_exit_on_completion
121
+ @semaphore = Mutex.new
122
+ @conditional_device_scans = []
123
+ @scans_observed = []
124
+ @execution_cycle_started = false
125
+
126
+ start_poller
127
+ end
128
+
129
+ #------------------------------------------------------------------------------------------------------
130
+ # Adds a scan to be observed
131
+ # scan_id: The ID of the scan to be observed.
132
+ #------------------------------------------------------------------------------------------------------
133
+ def add_scan_observed scan_id
134
+ puts "Obeserving scan #{scan_id}"
135
+ @scans_observed << scan_id
136
+ end
137
+
138
+ #------------------------------------------------------------------------------------------------------
139
+ # Removes a currently observed scan
140
+ # scan_id: The ID of the scan to be removed.
141
+ #------------------------------------------------------------------------------------------------------
142
+ def remover_scan_observed scan_id
143
+ @scans_observed.delete scan_id
144
+ end
145
+
146
+ #------------------------------------------------------------------------------------------------------
147
+ # Starts device site scans based on a particular condition, for now this is if the max amount of scans
148
+ # specified is greater than the amount of currently running scans.
149
+ #
150
+ # conditional_scan: A hash of informations used to start scanning
151
+ # ie : @[0] -> :site_id => 1 :devices => [192.168.1.1] :max_scans => 5 :listeners => [listerner_objects]
152
+ #-------------------------------------------------------------------------------------------------------
153
+ def add_cond_scan conditional_scan
154
+ if conditional_scan.nil?
155
+ raise ArgumentError 'Condtional scan arguement is null'
156
+ end
157
+
158
+ @semaphore.synchronize do
159
+ @conditional_device_scans << conditional_scan
160
+ if not @execution_cycle_started
161
+ @execution_cycle_started = true
162
+ end
163
+ end
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nexpose_scan_manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Christopher Lee
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-16 00:00:00.000000000 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nexpose
17
+ requirement: &27094380 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *27094380
26
+ - !ruby/object:Gem::Dependency
27
+ name: eventmachine-eventmachine
28
+ requirement: &27093600 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.12.9
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *27093600
37
+ description:
38
+ email: christopher_lee@rapid7.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - lib/scan_manager.rb
44
+ has_rdoc: true
45
+ homepage:
46
+ licenses: []
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 1.5.2
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Used for to start a managed scan and monitor their activity
69
+ test_files: []