ruby-nmap 0.10.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.document +1 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +31 -0
  5. data/ChangeLog.md +118 -71
  6. data/Gemfile +11 -5
  7. data/LICENSE.txt +1 -1
  8. data/README.md +88 -50
  9. data/Rakefile +5 -0
  10. data/UPGRADING.md +47 -0
  11. data/gemspec.yml +5 -5
  12. data/lib/nmap/command.rb +765 -0
  13. data/lib/nmap/version.rb +1 -1
  14. data/lib/nmap/xml/address.rb +38 -0
  15. data/lib/nmap/xml/cpe/url.rb +80 -0
  16. data/lib/nmap/xml/cpe.rb +47 -0
  17. data/lib/nmap/xml/hop.rb +22 -0
  18. data/lib/nmap/xml/host.rb +546 -0
  19. data/lib/nmap/xml/host_script.rb +26 -0
  20. data/lib/nmap/xml/hostname.rb +44 -0
  21. data/lib/nmap/xml/ip_id_sequence.rb +26 -0
  22. data/lib/nmap/xml/os.rb +131 -0
  23. data/lib/nmap/xml/os_class.rb +86 -0
  24. data/lib/nmap/xml/os_match.rb +22 -0
  25. data/lib/nmap/xml/port.rb +114 -0
  26. data/lib/nmap/xml/postscript.rb +26 -0
  27. data/lib/nmap/xml/prescript.rb +26 -0
  28. data/lib/nmap/xml/run_stat.rb +22 -0
  29. data/lib/nmap/xml/scan.rb +38 -0
  30. data/lib/nmap/xml/scan_task.rb +55 -0
  31. data/lib/nmap/xml/scanner.rb +22 -0
  32. data/lib/nmap/xml/script.rb +110 -0
  33. data/lib/nmap/xml/scripts.rb +33 -0
  34. data/lib/nmap/xml/sequence.rb +52 -0
  35. data/lib/nmap/xml/service.rb +172 -0
  36. data/lib/nmap/xml/status.rb +22 -0
  37. data/lib/nmap/xml/tcp_sequence.rb +48 -0
  38. data/lib/nmap/xml/tcp_ts_sequence.rb +26 -0
  39. data/lib/nmap/xml/traceroute.rb +73 -0
  40. data/lib/nmap/xml/uptime.rb +22 -0
  41. data/lib/nmap/xml.rb +31 -44
  42. data/spec/command_spec.rb +726 -0
  43. data/spec/fixtures/down_host_scan.xml +16 -0
  44. data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
  45. data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
  46. data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
  47. data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
  48. data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
  49. data/spec/{host_spec.rb → xml/host_spec.rb} +8 -8
  50. data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
  51. data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
  52. data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
  53. data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
  54. data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
  55. data/spec/{port_spec.rb → xml/port_spec.rb} +4 -5
  56. data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
  57. data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
  58. data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
  59. data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
  60. data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
  61. data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
  62. data/spec/xml/script_spec.rb +137 -0
  63. data/spec/xml/scripts_examples.rb +19 -0
  64. data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
  65. data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
  66. data/spec/{status_spec.rb → xml/status_spec.rb} +2 -2
  67. data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
  68. data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
  69. data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
  70. data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
  71. data/spec/xml_spec.rb +73 -44
  72. metadata +72 -66
  73. data/.travis.yml +0 -16
  74. data/lib/nmap/address.rb +0 -34
  75. data/lib/nmap/cpe/url.rb +0 -78
  76. data/lib/nmap/cpe.rb +0 -45
  77. data/lib/nmap/hop.rb +0 -20
  78. data/lib/nmap/host.rb +0 -587
  79. data/lib/nmap/host_script.rb +0 -18
  80. data/lib/nmap/hostname.rb +0 -42
  81. data/lib/nmap/ip_id_sequence.rb +0 -24
  82. data/lib/nmap/os.rb +0 -127
  83. data/lib/nmap/os_class.rb +0 -82
  84. data/lib/nmap/os_match.rb +0 -18
  85. data/lib/nmap/port.rb +0 -110
  86. data/lib/nmap/postscript.rb +0 -16
  87. data/lib/nmap/prescript.rb +0 -16
  88. data/lib/nmap/program.rb +0 -102
  89. data/lib/nmap/run_stat.rb +0 -20
  90. data/lib/nmap/scan.rb +0 -34
  91. data/lib/nmap/scan_task.rb +0 -53
  92. data/lib/nmap/scanner.rb +0 -18
  93. data/lib/nmap/scripts.rb +0 -71
  94. data/lib/nmap/sequence.rb +0 -50
  95. data/lib/nmap/service.rb +0 -170
  96. data/lib/nmap/status.rb +0 -18
  97. data/lib/nmap/task.rb +0 -387
  98. data/lib/nmap/tcp_sequence.rb +0 -46
  99. data/lib/nmap/tcp_ts_sequence.rb +0 -22
  100. data/lib/nmap/traceroute.rb +0 -71
  101. data/lib/nmap/uptime.rb +0 -20
  102. data/spec/scripts_examples.rb +0 -35
  103. data/spec/task_spec.rb +0 -150
@@ -0,0 +1,546 @@
1
+ require 'nmap/xml/status'
2
+ require 'nmap/xml/address'
3
+ require 'nmap/xml/hostname'
4
+ require 'nmap/xml/os'
5
+ require 'nmap/xml/port'
6
+ require 'nmap/xml/ip_id_sequence'
7
+ require 'nmap/xml/tcp_sequence'
8
+ require 'nmap/xml/tcp_ts_sequence'
9
+ require 'nmap/xml/uptime'
10
+ require 'nmap/xml/traceroute'
11
+ require 'nmap/xml/host_script'
12
+
13
+ require 'nokogiri'
14
+ require 'time'
15
+
16
+ module Nmap
17
+ class XML
18
+ #
19
+ # Wraps a `host` XML element.
20
+ #
21
+ # @since 1.0.0
22
+ #
23
+ class Host
24
+
25
+ include Enumerable
26
+
27
+ #
28
+ # Creates a new Host object.
29
+ #
30
+ # @param [Nokogiri::XML::Node] node
31
+ # The XML node that contains the host information.
32
+ #
33
+ def initialize(node)
34
+ @node = node
35
+ end
36
+
37
+ #
38
+ # The time the host was first scanned.
39
+ #
40
+ # @return [Time]
41
+ # The time the host was first scanned.
42
+ #
43
+ # @since 0.1.2
44
+ #
45
+ def start_time
46
+ @start_time ||= Time.at(@node['starttime'].to_i)
47
+ end
48
+
49
+ #
50
+ # The time the host was last scanned.
51
+ #
52
+ # @return [Time]
53
+ # The time the host was last scanned.
54
+ #
55
+ # @since 0.1.2
56
+ #
57
+ def end_time
58
+ @end_time ||= Time.at(@node['endtime'].to_i)
59
+ end
60
+
61
+ #
62
+ # Parses the status of the host.
63
+ #
64
+ # @return [Status]
65
+ # The status of the host.
66
+ #
67
+ def status
68
+ unless @status
69
+ status = @node.at_xpath('status')
70
+
71
+ @status = Status.new(
72
+ status['state'].to_sym,
73
+ status['reason'],
74
+ status['reason_ttl'].to_i
75
+ )
76
+ end
77
+
78
+ return @status
79
+ end
80
+
81
+ #
82
+ # Parses each address of the host.
83
+ #
84
+ # @yield [addr]
85
+ # Each parsed address will be pass to a given block.
86
+ #
87
+ # @yieldparam [Address] addr
88
+ # A address of the host.
89
+ #
90
+ # @return [Host, Enumerator]
91
+ # The host.
92
+ # If no block was given, an enumerator will be returned.
93
+ #
94
+ def each_address
95
+ return enum_for(__method__) unless block_given?
96
+
97
+ @node.xpath("address[@addr]").each do |addr|
98
+ address = Address.new(
99
+ addr['addrtype'].to_sym,
100
+ addr['addr'],
101
+ addr['vendor']
102
+ )
103
+
104
+ yield address
105
+ end
106
+
107
+ return self
108
+ end
109
+
110
+ #
111
+ # Parses the addresses of the host.
112
+ #
113
+ # @return [Array<Host>]
114
+ # The addresses of the host.
115
+ #
116
+ def addresses
117
+ each_address.to_a
118
+ end
119
+
120
+ #
121
+ # Parses the MAC address of the host.
122
+ #
123
+ # @return [String]
124
+ # The MAC address of the host.
125
+ #
126
+ def mac
127
+ @mac ||= if (addr = @node.at_xpath("address[@addrtype='mac']"))
128
+ addr['addr']
129
+ end
130
+ end
131
+
132
+ #
133
+ # Parses the MAC vendor of the host.
134
+ #
135
+ # @return [String]
136
+ # The Mac Vendor of the host.
137
+ #
138
+ # @since 0.8.0
139
+ #
140
+ def vendor
141
+ @vendor ||= if (vendor = @node.at_xpath("address/@vendor"))
142
+ vendor.inner_text
143
+ end
144
+ end
145
+
146
+ #
147
+ # Parses the IPv4 address of the host.
148
+ #
149
+ # @return [String]
150
+ # The IPv4 address of the host.
151
+ #
152
+ def ipv4
153
+ @ipv4 ||= if (addr = @node.at_xpath("address[@addrtype='ipv4']"))
154
+ addr['addr']
155
+ end
156
+ end
157
+
158
+ #
159
+ # Parses the IPv6 address of the host.
160
+ #
161
+ # @return [String]
162
+ # The IPv6 address of the host.
163
+ #
164
+ def ipv6
165
+ @ipv6 ||= if (addr = @node.at_xpath("address[@addrtype='ipv6']"))
166
+ addr['addr']
167
+ end
168
+ end
169
+
170
+ #
171
+ # The IP address of the host.
172
+ #
173
+ # @return [String]
174
+ # The IPv4 or IPv6 address of the host.
175
+ #
176
+ def ip
177
+ ipv6 || ipv4
178
+ end
179
+
180
+ #
181
+ # The address of the host.
182
+ #
183
+ # @return [String]
184
+ # The IP or MAC address of the host.
185
+ #
186
+ def address
187
+ ip || mac
188
+ end
189
+
190
+ #
191
+ # Parses the hostnames of the host.
192
+ #
193
+ # @yield [host]
194
+ # Each parsed hostname will be passed to the given block.
195
+ #
196
+ # @yieldparam [Hostname] host
197
+ # A hostname of the host.
198
+ #
199
+ # @return [Host, Enumerator]
200
+ # The host.
201
+ # If no block was given, an enumerator will be returned.
202
+ #
203
+ def each_hostname
204
+ return enum_for(__method__) unless block_given?
205
+
206
+ @node.xpath("hostnames/hostname[@name]").each do |host|
207
+ yield Hostname.new(host['type'],host['name'])
208
+ end
209
+
210
+ return self
211
+ end
212
+
213
+ #
214
+ # Parses the hostnames of the host.
215
+ #
216
+ # @return [Array<Hostname>]
217
+ # The hostnames of the host.
218
+ #
219
+ def hostnames
220
+ each_hostname.to_a
221
+ end
222
+
223
+ #
224
+ # The primary hostname of the host.
225
+ #
226
+ # @return [Hostname, nil]
227
+ #
228
+ # @since 0.8.0
229
+ #
230
+ def hostname
231
+ each_hostname.first
232
+ end
233
+
234
+ #
235
+ # Parses the OS guessing information of the host.
236
+ #
237
+ # @yield [os]
238
+ # If a block is given, it will be passed the OS guessing information.
239
+ #
240
+ # @yieldparam [OS] os
241
+ # The OS guessing information.
242
+ #
243
+ # @return [OS]
244
+ # The OS guessing information.
245
+ #
246
+ def os
247
+ @os ||= if (os = @node.at_xpath('os'))
248
+ OS.new(os)
249
+ end
250
+
251
+ yield @os if (@os && block_given?)
252
+ return @os
253
+ end
254
+
255
+ #
256
+ # Parses the Uptime analysis of the host.
257
+ #
258
+ # @yield [uptime]
259
+ # If a block is given, it will be passed the resulting object
260
+ #
261
+ # @yieldparam [Uptime]
262
+ # Uptime value.
263
+ #
264
+ # @return [Uptime]
265
+ # The parsed object.
266
+ #
267
+ # @since 0.7.0
268
+ #
269
+ def uptime
270
+ @uptime ||= if (uptime = @node.at_xpath('uptime'))
271
+ Uptime.new(
272
+ uptime['seconds'].to_i,
273
+ Time.parse(uptime['lastboot'])
274
+ )
275
+ end
276
+
277
+ yield @uptime if (@uptime && block_given?)
278
+ return @uptime
279
+ end
280
+
281
+ #
282
+ # Parses the TCP Sequence number analysis of the host.
283
+ #
284
+ # @yield [sequence]
285
+ # If a block is given, it will be passed the resulting object
286
+ #
287
+ # @yieldparam [TcpSequence] sequence
288
+ # TCP Sequence number analysis.
289
+ #
290
+ # @return [TcpSequence]
291
+ # The parsed object.
292
+ #
293
+ def tcp_sequence
294
+ @tcp_sequence ||= if (seq = @node.at_xpath('tcpsequence'))
295
+ TcpSequence.new(seq)
296
+ end
297
+
298
+ yield @tcp_sequence if (@tcp_sequence && block_given?)
299
+ return @tcp_sequence
300
+ end
301
+
302
+ #
303
+ # Parses the IPID sequence number analysis of the host.
304
+ #
305
+ # @yield [ipidsequence]
306
+ # If a block is given, it will be passed the resulting object
307
+ #
308
+ # @yieldparam [IpIdSequence] ipidsequence
309
+ # IPID Sequence number analysis.
310
+ #
311
+ # @return [IpIdSequence]
312
+ # The parsed object.
313
+ #
314
+ def ip_id_sequence
315
+ @ip_id_sequence ||= if (seq = @node.at_xpath('ipidsequence'))
316
+ IpIdSequence.new(seq)
317
+ end
318
+
319
+ yield @ip_id_sequence if (@ip_id_sequence && block_given?)
320
+ return @ip_id_sequence
321
+ end
322
+
323
+ #
324
+ # Parses the TCP Timestamp sequence number analysis of the host.
325
+ #
326
+ # @yield [tcptssequence]
327
+ # If a block is given, it will be passed the resulting object
328
+ #
329
+ # @yieldparam [TcpTsSequence] tcptssequence
330
+ # TCP Timestamp Sequence number analysis.
331
+ #
332
+ # @return [TcpTsSequence]
333
+ # The parsed object.
334
+ #
335
+ def tcp_ts_sequence
336
+ @tcp_ts_sequence ||= if (seq = @node.at_xpath('tcptssequence'))
337
+ TcpTsSequence.new(seq)
338
+ end
339
+
340
+ yield @tcp_ts_sequence if (@tcp_ts_sequence && block_given?)
341
+ return @tcp_ts_sequence
342
+ end
343
+
344
+ #
345
+ # Parses the scanned ports of the host.
346
+ #
347
+ # @yield [port]
348
+ # Each scanned port of the host.
349
+ #
350
+ # @yieldparam [Port] port
351
+ # A scanned port of the host.
352
+ #
353
+ # @return [Host, Enumerator]
354
+ # The host.
355
+ # If no block was given, an enumerator will be returned.
356
+ #
357
+ def each_port
358
+ return enum_for(__method__) unless block_given?
359
+
360
+ @node.xpath("ports/port").each do |port|
361
+ yield Port.new(port)
362
+ end
363
+
364
+ return self
365
+ end
366
+
367
+ #
368
+ # Parses the scanned ports of the host.
369
+ #
370
+ # @return [Array<Port>]
371
+ # The scanned ports of the host.
372
+ #
373
+ def ports
374
+ each_port.to_a
375
+ end
376
+
377
+ #
378
+ # Parses the open ports of the host.
379
+ #
380
+ # @yield [port]
381
+ # Each open port of the host.
382
+ #
383
+ # @yieldparam [Port] port
384
+ # An open scanned port of the host.
385
+ #
386
+ # @return [Host, Enumerator]
387
+ # The host.
388
+ # If no block was given, an enumerator will be returned.
389
+ #
390
+ def each_open_port
391
+ return enum_for(__method__) unless block_given?
392
+
393
+ @node.xpath("ports/port[state/@state='open']").each do |port|
394
+ yield Port.new(port)
395
+ end
396
+
397
+ return self
398
+ end
399
+
400
+ #
401
+ # Parses the open ports of the host.
402
+ #
403
+ # @return [Array<Port>]
404
+ # The open ports of the host.
405
+ #
406
+ def open_ports
407
+ each_open_port.to_a
408
+ end
409
+
410
+ #
411
+ # Parses the TCP ports of the host.
412
+ #
413
+ # @yield [port]
414
+ # Each TCP port of the host.
415
+ #
416
+ # @yieldparam [Port] port
417
+ # An TCP scanned port of the host.
418
+ #
419
+ # @return [Host, Enumerator]
420
+ # The host.
421
+ # If no block was given, an enumerator will be returned.
422
+ #
423
+ def each_tcp_port
424
+ return enum_for(__method__) unless block_given?
425
+
426
+ @node.xpath("ports/port[@protocol='tcp']").each do |port|
427
+ yield Port.new(port)
428
+ end
429
+
430
+ return self
431
+ end
432
+
433
+ #
434
+ # Parses the TCP ports of the host.
435
+ #
436
+ # @return [Array<Port>]
437
+ # The TCP ports of the host.
438
+ #
439
+ def tcp_ports
440
+ each_tcp_port.to_a
441
+ end
442
+
443
+ #
444
+ # Parses the UDP ports of the host.
445
+ #
446
+ # @yield [port]
447
+ # Each UDP port of the host.
448
+ #
449
+ # @yieldparam [Port] port
450
+ # An UDP scanned port of the host.
451
+ #
452
+ # @return [Host, Enumerator]
453
+ # The host.
454
+ # If no block was given, an enumerator will be returned.
455
+ #
456
+ def each_udp_port
457
+ return enum_for(__method__) unless block_given?
458
+
459
+ @node.xpath("ports/port[@protocol='udp']").each do |port|
460
+ yield Port.new(port)
461
+ end
462
+
463
+ return self
464
+ end
465
+
466
+ #
467
+ # Parses the UDP ports of the host.
468
+ #
469
+ # @return [Array<Port>]
470
+ # The UDP ports of the host.
471
+ #
472
+ def udp_ports
473
+ each_udp_port.to_a
474
+ end
475
+
476
+ #
477
+ # Parses the open ports of the host.
478
+ #
479
+ # @see each_open_port
480
+ #
481
+ def each(&block)
482
+ each_open_port(&block)
483
+ end
484
+
485
+ #
486
+ # The NSE scripts ran against the host.
487
+ #
488
+ # @return [HostScript, nil]
489
+ # Contains the host script output and data.
490
+ #
491
+ # @since 0.9.0
492
+ #
493
+ def host_script
494
+ @host_script ||= if (hostscript = @node.at_xpath('hostscript'))
495
+ HostScript.new(hostscript)
496
+ end
497
+ end
498
+
499
+ #
500
+ # Parses the traceroute information, if present.
501
+ #
502
+ # @yield [traceroute]
503
+ # If a block is given, it will be passed the traceroute information.
504
+ #
505
+ # @yieldparam [Traceroute] traceroute
506
+ # The traceroute information.
507
+ #
508
+ # @return [Traceroute]
509
+ # The traceroute information.
510
+ #
511
+ # @since 0.7.0
512
+ #
513
+ def traceroute
514
+ @traceroute ||= if (trace = @node.at_xpath('trace'))
515
+ Traceroute.new(trace)
516
+ end
517
+
518
+ yield @traceroute if (@traceroute && block_given?)
519
+ return @traceroute
520
+ end
521
+
522
+ #
523
+ # Converts the host to a String.
524
+ #
525
+ # @return [String]
526
+ # The hostname or address of the host.
527
+ #
528
+ # @see address
529
+ #
530
+ def to_s
531
+ (hostname || address).to_s
532
+ end
533
+
534
+ #
535
+ # Inspects the host.
536
+ #
537
+ # @return [String]
538
+ # The inspected host.
539
+ #
540
+ def inspect
541
+ "#<#{self.class}: #{self}>"
542
+ end
543
+
544
+ end
545
+ end
546
+ end
@@ -0,0 +1,26 @@
1
+ require 'nmap/xml/scripts'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Represents the `hostscript` element.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class HostScript
11
+
12
+ include Scripts
13
+
14
+ #
15
+ # Initializes the HostScript object.
16
+ #
17
+ # @param [Nokogiri::XML::Node] node
18
+ # The XML node that contains the host information.
19
+ #
20
+ def initialize(node)
21
+ @node = node
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ module Nmap
2
+ class XML
3
+ #
4
+ # Represents a hostname.
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ class Hostname < Struct.new(:type, :name)
9
+
10
+ #
11
+ # Determines if the hostname was specified by the user.
12
+ #
13
+ # @return [Boolean]
14
+ #
15
+ # @since 0.8.0
16
+ #
17
+ def user?
18
+ self.type == 'user'
19
+ end
20
+
21
+ #
22
+ # Determines if the hostname is a DNS `PTR`.
23
+ #
24
+ # @return [Boolean]
25
+ #
26
+ # @since 0.8.0
27
+ #
28
+ def ptr?
29
+ self.type == 'PTR'
30
+ end
31
+
32
+ #
33
+ # Converts the hostname to a String.
34
+ #
35
+ # @return [String]
36
+ # The name of the host.
37
+ #
38
+ def to_s
39
+ self.name.to_s
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ require 'nmap/xml/sequence'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Represents an IP ID.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class IpIdSequence < Sequence
11
+
12
+ #
13
+ # Converts the IpidSequence class to a String.
14
+ #
15
+ # @return [String]
16
+ # The String form of the object.
17
+ #
18
+ # @since 0.5.0
19
+ #
20
+ def to_s
21
+ "description=#{description.inspect} values=#{values.inspect}"
22
+ end
23
+
24
+ end
25
+ end
26
+ end