firescan 0.07

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 (77) hide show
  1. data/LICENSE.txt +202 -0
  2. data/README.txt +37 -0
  3. data/USAGE.txt +43 -0
  4. data/VERSION.txt +4 -0
  5. data/bin/firescan +4 -0
  6. data/build +7 -0
  7. data/doc/Example.html +224 -0
  8. data/doc/Firebind.html +213 -0
  9. data/doc/Firebind/Client.html +750 -0
  10. data/doc/Firebind/Portspec.html +390 -0
  11. data/doc/Firebind/Scan.html +413 -0
  12. data/doc/Firebind/ScanError.html +277 -0
  13. data/doc/Firebind/ScanState.html +1015 -0
  14. data/doc/Firebind/SimpleProtocol.html +292 -0
  15. data/doc/Firebind/TcpTransport.html +481 -0
  16. data/doc/Firebind/Transport.html +275 -0
  17. data/doc/Firebind/UdpTransport.html +472 -0
  18. data/doc/LICENSE_txt.html +323 -0
  19. data/doc/README_txt.html +171 -0
  20. data/doc/Runner.html +166 -0
  21. data/doc/TestPortspec.html +289 -0
  22. data/doc/Tools.html +321 -0
  23. data/doc/USAGE_txt.html +184 -0
  24. data/doc/VERSION_txt.html +126 -0
  25. data/doc/build.html +125 -0
  26. data/doc/created.rid +22 -0
  27. data/doc/doc/created_rid.html +121 -0
  28. data/doc/firescan_gemspec.html +140 -0
  29. data/doc/images/add.png +0 -0
  30. data/doc/images/arrow_up.png +0 -0
  31. data/doc/images/brick.png +0 -0
  32. data/doc/images/brick_link.png +0 -0
  33. data/doc/images/bug.png +0 -0
  34. data/doc/images/bullet_black.png +0 -0
  35. data/doc/images/bullet_toggle_minus.png +0 -0
  36. data/doc/images/bullet_toggle_plus.png +0 -0
  37. data/doc/images/date.png +0 -0
  38. data/doc/images/delete.png +0 -0
  39. data/doc/images/find.png +0 -0
  40. data/doc/images/loadingAnimation.gif +0 -0
  41. data/doc/images/macFFBgHack.png +0 -0
  42. data/doc/images/package.png +0 -0
  43. data/doc/images/page_green.png +0 -0
  44. data/doc/images/page_white_text.png +0 -0
  45. data/doc/images/page_white_width.png +0 -0
  46. data/doc/images/plugin.png +0 -0
  47. data/doc/images/ruby.png +0 -0
  48. data/doc/images/tag_blue.png +0 -0
  49. data/doc/images/tag_green.png +0 -0
  50. data/doc/images/transparent.png +0 -0
  51. data/doc/images/wrench.png +0 -0
  52. data/doc/images/wrench_orange.png +0 -0
  53. data/doc/images/zoom.png +0 -0
  54. data/doc/index.html +118 -0
  55. data/doc/js/darkfish.js +155 -0
  56. data/doc/js/jquery.js +18 -0
  57. data/doc/js/navigation.js +142 -0
  58. data/doc/js/search.js +94 -0
  59. data/doc/js/search_index.js +1 -0
  60. data/doc/js/searcher.js +228 -0
  61. data/doc/rdoc.css +595 -0
  62. data/doc/table_of_contents.html +230 -0
  63. data/firescan.gemspec +18 -0
  64. data/lib/example.rb +20 -0
  65. data/lib/firebind/client.rb +308 -0
  66. data/lib/firebind/portspec.rb +107 -0
  67. data/lib/firebind/scan.rb +288 -0
  68. data/lib/firebind/scan_error.rb +32 -0
  69. data/lib/firebind/scan_state.rb +140 -0
  70. data/lib/firebind/simple_protocol.rb +59 -0
  71. data/lib/firebind/tcp_transport.rb +184 -0
  72. data/lib/firebind/tools.rb +107 -0
  73. data/lib/firebind/transport.rb +44 -0
  74. data/lib/firebind/udp_transport.rb +174 -0
  75. data/test/portspec_test.rb +53 -0
  76. data/test/runner.rb +7 -0
  77. metadata +136 -0
@@ -0,0 +1,107 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ module Firebind
18
+
19
+ # This data structure encapsulates the properties and operations of a port list. Arbitrary lists of comma separated
20
+ # and dashed-ranges can be converted into a full array of ports for a list.
21
+ # This class will eventually require the full complement of set arithmetic
22
+ class Portspec
23
+
24
+ attr_reader :ports, :compiled_list
25
+
26
+ # Supply either a string or int array
27
+ # examples: 1,2,3,55,10-20 or [56,34,443,25,6000]
28
+ def initialize(port_list)
29
+
30
+ port_map = Hash.new
31
+ if port_list.kind_of?(Array) # numeric array, possible dups and out of range values
32
+ port_list.each do |port|
33
+ port_map[port] = port
34
+ end
35
+
36
+ elsif port_list.kind_of?(String) # comma and dash port list, possible dups and out of range values
37
+ #validate
38
+ if port_list !~ /^[0-9,\-]+$/
39
+ raise ArgumentError, 'Bad port specification '+port_list, caller
40
+ end
41
+ port_list.split(/\s*,\s*/).each do |part|
42
+ if part =~ /[\-]+/ # is this a range?
43
+ first,last = part.split(/\-/)
44
+ #noinspection RubyForLoopInspection
45
+ for port in first.gsub(/[^0-9]/,'').to_i..last.gsub(/[^0-9]/,'').to_i
46
+ port_map[port] = port
47
+ end
48
+ else
49
+ port = part.gsub(/[^0-9]/,'').to_i
50
+ port_map[port] = port
51
+ end
52
+ end
53
+ end
54
+
55
+ # sort the map and insert the expanded port list into our @ports array
56
+ @ports = Array.new
57
+ i = 0
58
+ port_map.sort_by {|number,flag|number}.each do |port,flag|
59
+ if port < 1 or port > 65535
60
+ raise ArgumentError, 'Bad port number '+port.to_s, caller
61
+ end
62
+ @ports[i] = port
63
+ i += 1
64
+ end
65
+
66
+ # generate a compiled port specification based on the ordered list in array
67
+ last_port = -1
68
+ building_a_range = false
69
+ @compiled_list = ''
70
+ @ports.each_with_index do |port,index|
71
+ if port == (last_port+1)
72
+ # continue building range
73
+ building_a_range = true
74
+ # are we at the end of the array? if so we're not coming back here...
75
+ if index == @ports.length-1
76
+ @compiled_list += '-' + port.to_s
77
+ end
78
+ else
79
+ if building_a_range
80
+ # end of the range
81
+ @compiled_list += '-' + last_port.to_s + ',' + port.to_s
82
+ building_a_range = false
83
+ else
84
+ @compiled_list += ',' unless @compiled_list.length == 0
85
+ @compiled_list += port.to_s
86
+ end
87
+ end
88
+ last_port = port
89
+ end
90
+ end
91
+
92
+ def to_s
93
+ @compiled_list
94
+ end
95
+
96
+ def size
97
+ @ports.length
98
+ end
99
+
100
+ end
101
+
102
+ #ports = '6,5,4445,4,3,2,50-60,666,69,55,65534,65533'
103
+ #ps = Firebind::Portspec.new(ports)
104
+ #puts ports + " ==> " + ps.to_s
105
+
106
+ end
107
+
@@ -0,0 +1,288 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require 'net/http'
18
+ require 'uri'
19
+ require 'json'
20
+ require 'observer'
21
+ require_relative 'simple_protocol'
22
+ require_relative 'portspec'
23
+ require_relative 'tools'
24
+ require_relative 'scan_state'
25
+
26
+ # This module encapsulates client-side path scanning functionality for use with an associated Firebind server.
27
+ module Firebind
28
+
29
+
30
+ # This is the primary API object for performing scans. Simply supply the necessary arguments to create a Scan
31
+ # and call the scan() method
32
+ #--
33
+ #noinspection RubyTooManyInstanceVariablesInspection
34
+ class Scan
35
+ include Observable
36
+ include Tools
37
+
38
+ # Create a new Scan
39
+ #
40
+ #--
41
+ # @param [Object] command_server
42
+ # @param [Object] ports
43
+ def initialize (command_server, ports, transport, timeout=5000, protocol=:SimpleProtocol, username=NIL, password=NIL)
44
+ @command_server = command_server
45
+ @portspec = Firebind::Portspec.new(ports)
46
+ @timeout = timeout
47
+ @protocol = protocol
48
+ @username = username
49
+ @password = password
50
+ @transport = transport
51
+ @done = false
52
+ @state = ScanState.new(command_server,protocol,transport,@portspec,timeout)
53
+
54
+
55
+ end
56
+
57
+ # Perform the path scan
58
+ #
59
+ # :call-seq:
60
+ # scan -> ScanState
61
+ #
62
+ def scan
63
+
64
+ api_start
65
+ changed
66
+ notify_observers(@state)
67
+
68
+ if @done
69
+ return @state
70
+ end
71
+
72
+ case @protocol
73
+ when :SimpleProtocol
74
+ scan_protocol = SimpleProtocol.new(@state.guid,@state.echo_server,@state.transport,@timeout)
75
+
76
+ else
77
+ scan_protocol = SimpleProtocol.new(@state.guid,@state.echo_server,@state.transport,@timeout)
78
+ end
79
+
80
+
81
+ @portspec.ports.each do |port|
82
+ break if @done
83
+ begin
84
+
85
+ if @state.ports_scanned > 0
86
+ # make sure we don't fry the routers
87
+ debug("waiting #{@state.port_delay_seconds}s for next port echo")
88
+ IO.select(nil,nil,nil,@state.port_delay_seconds)
89
+ end
90
+
91
+ # callback for port start
92
+ @state.on_port_start(port)
93
+ changed
94
+ notify_observers(@state)
95
+
96
+ # perform the path echo send/receive
97
+ scan_protocol.echo(port)
98
+ port_result_code = $result_codes[:SUCCESS]
99
+
100
+ rescue Firebind::ScanError => error
101
+ debug "error on port #{port} #{error.to_s}"
102
+ case error.status_code
103
+ when :HANDSHAKE_CONNECTION_TIME_OUT,
104
+ :HANDSHAKE_CONNECTION_INITIATION_FAILURE,
105
+ :HANDSHAKE_CONNECTION_REFUSED,
106
+ :HANDSHAKE_CONNECTION_COMPLETION_FAILURE,
107
+ :PAYLOAD_REFUSED_ON_RECV,
108
+ :PAYLOAD_TIMED_OUT_ON_RECV,
109
+ :PAYLOAD_ERROR_ON_RECV,
110
+ :PAYLOAD_MISMATCH_ON_RECV,
111
+ :FAILURE_ON_PAYLOAD_SEND
112
+
113
+ # try skipping
114
+ port_result_code = $result_codes[error.status_code]
115
+ if api_skip port
116
+
117
+ else
118
+
119
+ end
120
+
121
+ else # status_code is not skippable
122
+ @state.on_error(error.status_code)
123
+ changed
124
+ notify_observers(@state)
125
+ raise error
126
+
127
+
128
+ end
129
+
130
+ ensure
131
+ # callback for port complete - success/open
132
+ @state.on_port_complete(port,port_result_code)
133
+ changed
134
+ notify_observers(@state)
135
+ end
136
+
137
+ end
138
+
139
+ api_update
140
+
141
+ if @portspec.size == @state.ports_scanned
142
+ @state.on_scan_complete($client_scan_completed)
143
+ changed
144
+ notify_observers(@state)
145
+ end
146
+
147
+ #update
148
+ @state
149
+ end
150
+
151
+ def stop
152
+ puts 'setting flags'
153
+ @stop_requested = true
154
+ @done = true
155
+ api_stop
156
+ api_update
157
+ end
158
+
159
+ private
160
+
161
+ # perform an Identify API call to the server, for authentication testing
162
+ def api_identify
163
+ uri = URI.parse("http://#{@command_server}/api/user")
164
+ http = Net::HTTP.new(uri.host, uri.port) # create http client
165
+ request = Net::HTTP::Head.new(uri.request_uri) # create request object
166
+ request.basic_auth(@username, @password)
167
+
168
+ begin
169
+ response = http.request(request)
170
+ rescue
171
+ debug "Identify API call failed #{$!}"
172
+ return false
173
+ end
174
+
175
+ '1001' == response['status']
176
+ end
177
+
178
+ # perform a Scan API call to the server to initiate a path scan sequence
179
+ def api_start
180
+ uri = URI.parse("http://#{@command_server}/api/scan")
181
+ http = Net::HTTP.new(uri.host, uri.port) # create http client
182
+ request = Net::HTTP::Post.new(uri.request_uri)
183
+ request.basic_auth(@username, @password)
184
+
185
+ transport_proto = if @transport == :UDP then 'udp' else 'tcp' end
186
+
187
+ data = {portSpec:@portspec.to_s,protocol:transport_proto}
188
+ request.body = data.to_json
189
+
190
+ #noinspection RubyStringKeysInHashInspection
191
+ #request.set_form_data({'portSpec' => @portspec.to_s, 'protocol' => 'TCP'})
192
+
193
+ begin
194
+ response = http.request(request)
195
+ rescue # can't connect
196
+ @state.on_start_failure($command_server_unavailable)
197
+ @state.message = @command_server
198
+ @done = true
199
+ return
200
+ end
201
+
202
+ result = JSON.parse response.body
203
+ if 2000 == result['status']
204
+ # we're ok to go
205
+ @state.on_scan_start(result['guid'],result['echoHost'],result['portDelay'])
206
+ else
207
+ @state.on_start_failure(result['status'])
208
+ @done = true
209
+ #raise ('scan request failed with status '+result['status'].to_s)
210
+ end
211
+
212
+ true
213
+ end
214
+
215
+ # perform a Skip API call to the server
216
+ def api_skip(port)
217
+ begin
218
+ uri = URI.parse("http://#{@command_server}/api/scan/#{@state.echo_server}/#{@state.guid.to_s}/#{port.to_s}")
219
+ http = Net::HTTP.new(uri.host, uri.port) # create http client
220
+ request = Net::HTTP::Patch.new(uri.request_uri)
221
+ request.basic_auth(@username, @password)
222
+ verbose "skipping port #{port}"
223
+ response = http.request(request)
224
+ if '5000' == response['status']
225
+ debug "successful skip for port #{port}"
226
+ true
227
+ else
228
+ debug "unsuccessful skip for port #{port} response was #{response['status']}"
229
+ false
230
+ end
231
+ rescue
232
+ debug "Skip API call failed with #{$!}"
233
+ false
234
+ end
235
+ end
236
+
237
+ # perform a Stop API call to the server
238
+ def api_stop
239
+ uri = URI.parse("http://#{@command_server}/api/scan/#{@state.echo_server}/#{@state.guid.to_s}")
240
+ debug "stopping scan with #{uri}"
241
+ http = Net::HTTP.new(uri.host, uri.port) # create http client
242
+ request = Net::HTTP::Delete.new(uri.request_uri)
243
+ request.basic_auth(@username, @password)
244
+ begin
245
+ response = http.request(request)
246
+ rescue
247
+ debug "Stop API call failed #{$!}"
248
+ return false
249
+ end
250
+ @state.on_scan_stop
251
+ '9000' == response['status']
252
+ end
253
+
254
+ # perform an Update API call to the server
255
+ def api_update
256
+ uri = URI.parse("http://#{@command_server}/api/scan/#{@state.echo_server}/#{@state.guid.to_s}")
257
+ http = Net::HTTP.new(uri.host, uri.port) # create http client
258
+ request = Net::HTTP::Put.new(uri.request_uri)
259
+ request.basic_auth(@username, @password)
260
+
261
+ data = Array.new
262
+ @state.result_map.each do |code,ports|
263
+ ps = Portspec.new(ports)
264
+ status = if code == $success then 'Passed' else 'Failed' end
265
+ data << { guid:@state.guid, serverId:@state.echo_server, portSpec:ps.to_s, statusCode:code, status:status}
266
+ end
267
+
268
+ test_status = if @state.current_state == :SCAN_COMPLETE then 'Success' else 'Failed' end
269
+
270
+ #build json payload with results
271
+ report = { clientReport: { guid:@state.guid, serverId:@state.echo_server, testStatus:test_status, uid:@username},
272
+ clientReportData: data }
273
+ #jj report
274
+ json = report.to_json
275
+ request.body = json
276
+
277
+ begin
278
+ response = http.request(request)
279
+ rescue
280
+ debug "Update API call failed #{$!}"
281
+ return false
282
+ end
283
+
284
+ '9000' == response['status']
285
+ end
286
+
287
+ end
288
+ end
@@ -0,0 +1,32 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ module Firebind
18
+ class ScanError < IOError
19
+
20
+ attr_reader :status_code
21
+
22
+ def initialize(status_code, error=nil)
23
+ @status_code = status_code
24
+ @error = error
25
+ end
26
+
27
+ def to_s
28
+ "ScanError status_code:#{@status_code} cause:#{@error.to_s}"
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,140 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require_relative 'tools'
18
+ module Firebind
19
+
20
+ #
21
+ # Scan lifecycle states
22
+ # SCAN_SETUP
23
+ # SCAN_START
24
+ # PORT_START
25
+ # PORT_TICK
26
+ # PORT_COMPLETE
27
+ # ...
28
+ # SCAN_STOP or SCAN_COMPLETE or START_FAILURE or ERROR
29
+ #
30
+ #noinspection RubyTooManyInstanceVariablesInspection
31
+ class ScanState
32
+ include Tools
33
+
34
+ attr_reader :current_state, :guid, :echo_server, :protocol, :transport, :portspec, :port, :port_delay, :status_code,
35
+ :port_result_code, :ports_scanned, :last_duration, :result_map, :command_server, :timeout
36
+ attr_accessor :message
37
+
38
+ # @param [Firebind::Portspec] portspec
39
+ def initialize(command_server,protocol,transport,portspec,timeout)
40
+ @command_server = command_server
41
+ @current_state = :SCAN_SETUP
42
+ @protocol = protocol
43
+ @transport = transport
44
+ @portspec = portspec
45
+ @timeout = timeout
46
+ @guid = NIL
47
+ @echo_server = NIL
48
+ @port = 0
49
+ @last_duration = 0
50
+ @ports_scanned = 0
51
+ @result_map = Hash.new {|hash,key| hash[key]=[]} # block form
52
+ @message = NIL
53
+ end
54
+
55
+ def to_s
56
+ "#{@current_state.to_s} port #{@port} results #{@result_map}"
57
+ end
58
+
59
+ # lifecycle methods
60
+ def on_scan_start(guid,echo_server,port_delay)
61
+ @current_state = :SCAN_START
62
+ @guid = guid
63
+ @echo_server = echo_server
64
+ @port_delay = port_delay
65
+ end
66
+
67
+ def on_start_failure(status_code)
68
+ @current_state = :START_FAILURE
69
+ @status_code = status_code
70
+ end
71
+
72
+ def on_port_start(port)
73
+ @current_state = :PORT_START
74
+ @port = port
75
+ @port_start_time = Time.now
76
+ end
77
+
78
+ def on_port_tick
79
+ @current_state = :PORT_TICK
80
+ end
81
+
82
+ # @param [Object] port
83
+ def on_port_complete(port,port_result_code)
84
+ @port_end_time = Time.now
85
+ @current_state = :PORT_COMPLETE
86
+ @port = port
87
+ @port_result_code = port_result_code
88
+ @ports_scanned += 1
89
+ @result_map[port_result_code] << port
90
+ end
91
+
92
+ def on_scan_complete(status_code)
93
+ @current_state = :SCAN_COMPLETE
94
+ @status_code = status_code
95
+ end
96
+
97
+ def on_scan_stop
98
+ @current_state = :SCAN_STOPPED
99
+ end
100
+
101
+ def on_error(status_code)
102
+ @current_state = :ERROR
103
+ @status_code = status_code
104
+ end
105
+
106
+ # data methods
107
+ def port_duration
108
+ (((@port_end_time - @port_start_time) * 1000)+0.5).to_i
109
+ end
110
+
111
+ def percent_complete
112
+ ((@ports_scanned.to_f / @portspec.size.to_f) * 100).to_i
113
+ end
114
+
115
+ # return a Portspec of the open ports for this scan
116
+ def open_ports
117
+ Portspec.new(@result_map[$success])
118
+ end
119
+
120
+ # return a Portspec of the closed ports for this scan
121
+ def closed_ports
122
+ closed = Array.new
123
+ @result_map.each do |code,ports|
124
+ closed += ports unless code == $success
125
+ end
126
+ Portspec.new(closed)
127
+ end
128
+
129
+ def port_delay_seconds
130
+ @port_delay.to_f / 1000
131
+ end
132
+
133
+ def description(port_result_code)
134
+ $result_code_messages[port_result_code]
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+