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,52 @@
1
+ module Nmap
2
+ class XML
3
+ #
4
+ # Base class for all Sequence classes.
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ class Sequence
9
+
10
+ #
11
+ # Creates a new sequence object.
12
+ #
13
+ # @param [Nokogiri::XML::Node] node
14
+ # The node that contains the sequence information.
15
+ #
16
+ # @since 0.5.0
17
+ #
18
+ def initialize(node)
19
+ @node = node
20
+ end
21
+
22
+ #
23
+ # The description of the sequence.
24
+ #
25
+ # @return [String]
26
+ # The sequence class from nmap.
27
+ #
28
+ # @since 0.5.0
29
+ #
30
+ def description
31
+ @description ||= @node['class']
32
+ end
33
+
34
+ #
35
+ # The values within the sequence.
36
+ #
37
+ # @return [Array<Numeric>]
38
+ # A sample of sequence numbers taken by nmap.
39
+ #
40
+ # @since 0.5.0
41
+ #
42
+ def values
43
+ @values ||= if @node['values']
44
+ @node['values'].split(',').map { |value| value.to_i(16) }
45
+ else
46
+ []
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,172 @@
1
+ require 'nmap/xml/cpe'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Wraps a `service` XML element.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class Service
11
+
12
+ include CPE
13
+
14
+ #
15
+ # Creates a new OS object.
16
+ #
17
+ # @param [Nokogiri::XML::Node] node
18
+ # The node that contains the OS guessing information.
19
+ #
20
+ def initialize(node)
21
+ @node = node
22
+ end
23
+
24
+ #
25
+ # The name of the service.
26
+ #
27
+ # @return [String]
28
+ # The service name.
29
+ #
30
+ def name
31
+ @name ||= @node.get_attribute('name')
32
+ end
33
+
34
+ #
35
+ # Determines if the service requires SSL.
36
+ #
37
+ # @return [Boolean]
38
+ # Checks whether the `tunnel` XML attribute is `ssl`.
39
+ #
40
+ # @since 0.7.0
41
+ #
42
+ def ssl?
43
+ (@ssl ||= @node['tunnel']) == 'ssl'
44
+ end
45
+
46
+ #
47
+ # The application protocol used by the service.
48
+ #
49
+ # @return [String]
50
+ # The `proto` XML attribute.
51
+ #
52
+ # @since 0.7.0
53
+ #
54
+ def protocol
55
+ @protocol ||= @node['proto']
56
+ end
57
+
58
+ #
59
+ # The product of the service.
60
+ #
61
+ # @return [String]
62
+ # The product name.
63
+ #
64
+ def product
65
+ @product ||= @node.get_attribute('product')
66
+ end
67
+
68
+ #
69
+ # The version of the service.
70
+ #
71
+ # @return [String]
72
+ # The service version.
73
+ #
74
+ def version
75
+ @version ||= @node.get_attribute('version')
76
+ end
77
+
78
+ #
79
+ # The extra information from the service scan.
80
+ #
81
+ # @return [String]
82
+ # The `extrainfo` XML attribute.
83
+ #
84
+ # @since 0.7.0
85
+ #
86
+ def extra_info
87
+ @extra_info ||= @node['extrainfo']
88
+ end
89
+
90
+ #
91
+ # The hostname reported by the service.
92
+ #
93
+ # @return [String]
94
+ # The reported hostname.
95
+ #
96
+ def hostname
97
+ @hostname ||= @node.get_attribute('hostname')
98
+ end
99
+
100
+ #
101
+ # The reported OS type.
102
+ #
103
+ # @return [String]
104
+ # The `ostype` XML attribute.
105
+ #
106
+ # @since 0.7.0
107
+ #
108
+ def os_type
109
+ @os_type ||= @node['ostype']
110
+ end
111
+
112
+ #
113
+ # The reported device type.
114
+ #
115
+ # @return [String]
116
+ # The `devicetype` XML attribute.
117
+ #
118
+ # @since 0.7.0
119
+ #
120
+ def device_type
121
+ @device_type ||= @node['devicetype']
122
+ end
123
+
124
+ #
125
+ # The fingerprint method used to identify the service.
126
+ #
127
+ # @return [Symbol]
128
+ # The fingerprint method.
129
+ #
130
+ def fingerprint_method
131
+ @fingerprint_method ||= @node.get_attribute('method').to_sym
132
+ end
133
+
134
+ #
135
+ # The actual fingerprint
136
+ #
137
+ # @return [String]
138
+ # The fingerprint
139
+ #
140
+ # @since 0.7.0
141
+ #
142
+ def fingerprint
143
+ @fingerprint ||= @node.get_attribute('servicefp')
144
+ end
145
+
146
+ #
147
+ # The confidence score of the service fingerprinting.
148
+ #
149
+ # @return [Integer]
150
+ # The confidence score.
151
+ #
152
+ def confidence
153
+ @confidence ||= @node.get_attribute('conf').to_i
154
+ end
155
+
156
+ #
157
+ # Converts the service to a String.
158
+ #
159
+ # @return [String]
160
+ # String containing {#product} and {#version}, or {#name}.
161
+ #
162
+ def to_s
163
+ if (product && version)
164
+ "#{product} #{version}"
165
+ else
166
+ name
167
+ end
168
+ end
169
+
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,22 @@
1
+ module Nmap
2
+ class XML
3
+ #
4
+ # Represents the Status of a {Host}.
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ class Status < Struct.new(:state, :reason, :reason_ttl)
9
+
10
+ #
11
+ # Converts the status to a String.
12
+ #
13
+ # @return [String]
14
+ # The state.
15
+ #
16
+ def to_s
17
+ self.state.to_s
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ require 'nmap/xml/sequence'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Represents a TCP sequence number.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class TcpSequence < Sequence
11
+
12
+ #
13
+ # @return [Numeric]
14
+ # The difficulty index from nmap
15
+ #
16
+ # @since 0.5.0
17
+ #
18
+ def index
19
+ @index ||= if (index_string = @node['index'])
20
+ index_string.to_i
21
+ end
22
+ end
23
+
24
+ #
25
+ # @return [String]
26
+ # The difficulty description from nmap
27
+ #
28
+ # @since 0.5.0
29
+ #
30
+ def difficulty
31
+ @difficulty ||= @node['difficulty']
32
+ end
33
+
34
+ #
35
+ # Converts the TcpSequence class to a String.
36
+ #
37
+ # @return [String]
38
+ # The String form of the object.
39
+ #
40
+ # @since 0.5.0
41
+ #
42
+ def to_s
43
+ "index=#{index} difficulty=#{difficulty.inspect} values=#{values.inspect}"
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ require 'nmap/xml/sequence'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Represents a TCP timestamp.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class TcpTsSequence < Sequence
11
+
12
+ #
13
+ # Converts the TcpTsSequence 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
@@ -0,0 +1,73 @@
1
+ require 'nmap/xml/hop'
2
+
3
+ module Nmap
4
+ class XML
5
+ #
6
+ # Wraps the `trace` XML element.
7
+ #
8
+ # @since 1.0.0
9
+ #
10
+ class Traceroute
11
+
12
+ include Enumerable
13
+
14
+ #
15
+ # Creates a new traceroute.
16
+ #
17
+ # @param [Nokogiri::XML::Element] node
18
+ # The `trace` XML element.
19
+ #
20
+ def initialize(node)
21
+ @node = node
22
+ end
23
+
24
+ #
25
+ # The port used for the traceroute.
26
+ #
27
+ # @return [Integer, nil]
28
+ # The `port` XML attribute.
29
+ #
30
+ def port
31
+ @port ||= if @node['port']
32
+ @node['port'].to_i
33
+ end
34
+ end
35
+
36
+ #
37
+ # The protocol used for the traceroute.
38
+ #
39
+ # @return [Symbol, nil]
40
+ # The `proto` XML element.
41
+ #
42
+ def protocol
43
+ @protocol ||= if @node['proto']
44
+ @node['proto'].to_sym
45
+ end
46
+ end
47
+
48
+ #
49
+ # Parses the traceroute information for the host.
50
+ #
51
+ # @yield [hop]
52
+ # Each hop to the host.
53
+ #
54
+ # @yieldparam [Hop] hop
55
+ # A hop to the host.
56
+ #
57
+ # @return [Traceroute, Enumerator]
58
+ # The traceroute.
59
+ # If no block was given, an enumerator will be returned.
60
+ #
61
+ def each
62
+ return enum_for(__method__) unless block_given?
63
+
64
+ @node.xpath('hop').each do |hop|
65
+ yield Hop.new(hop['ipaddr'],hop['host'],hop['ttl'],hop['rtt'])
66
+ end
67
+
68
+ return self
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,22 @@
1
+ module Nmap
2
+ class XML
3
+ #
4
+ # Wraps a `uptime` XML element.
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ class Uptime < Struct.new(:seconds, :last_boot)
9
+
10
+ #
11
+ # Converts the uptime object to a String.
12
+ #
13
+ # @return [String]
14
+ # The String form of the Uptime.
15
+ #
16
+ def to_s
17
+ "uptime: #{self.seconds} (#{self.last_boot})"
18
+ end
19
+
20
+ end
21
+ end
22
+ end
data/lib/nmap/xml.rb CHANGED
@@ -1,10 +1,10 @@
1
- require 'nmap/scanner'
2
- require 'nmap/scan_task'
3
- require 'nmap/scan'
4
- require 'nmap/host'
5
- require 'nmap/run_stat'
6
- require 'nmap/prescript'
7
- require 'nmap/postscript'
1
+ require 'nmap/xml/scanner'
2
+ require 'nmap/xml/scan_task'
3
+ require 'nmap/xml/scan'
4
+ require 'nmap/xml/host'
5
+ require 'nmap/xml/run_stat'
6
+ require 'nmap/xml/prescript'
7
+ require 'nmap/xml/postscript'
8
8
 
9
9
  require 'nokogiri'
10
10
 
@@ -16,31 +16,36 @@ module Nmap
16
16
 
17
17
  include Enumerable
18
18
 
19
+ # The parsed XML document.
20
+ #
21
+ # @return [Nokogiri::XML]
22
+ #
23
+ # @api private
24
+ attr_reader :doc
25
+
19
26
  # Path of the Nmap XML scan file
27
+ #
28
+ # @return [String, nil]
20
29
  attr_reader :path
21
30
 
22
31
  #
23
32
  # Creates a new XML object.
24
33
  #
25
- # @param [Nokogiri::XML::Document, IO, String] document
34
+ # @param [Nokogiri::XML::Document] doc
26
35
  # The path to the Nmap XML scan file or Nokogiri::XML::Document.
27
36
  #
37
+ # @param [String, nil] path
38
+ # The optional path the XML was loaded from.
39
+ #
28
40
  # @yield [xml]
29
41
  # If a block is given, it will be passed the new XML object.
30
42
  #
31
43
  # @yieldparam [XML] xml
32
44
  # The newly created XML object.
33
45
  #
34
- def initialize(document)
35
- case document
36
- when Nokogiri::XML::Document
37
- @doc = document
38
- when IO, StringIO
39
- @doc = Nokogiri::XML(document)
40
- else
41
- @path = File.expand_path(document)
42
- @doc = File.open(@path) { |file| Nokogiri::XML(file) }
43
- end
46
+ def initialize(doc, path: nil)
47
+ @doc = doc
48
+ @path = File.expand_path(path) if path
44
49
 
45
50
  yield self if block_given?
46
51
  end
@@ -63,15 +68,6 @@ module Nmap
63
68
  new(Nokogiri::XML(text),&block)
64
69
  end
65
70
 
66
- #
67
- # @deprecated Use {parse} instead.
68
- #
69
- # @since 0.7.0
70
- #
71
- def self.load(text,&block)
72
- parse(text,&block)
73
- end
74
-
75
71
  #
76
72
  # Creates a new XML object from the file.
77
73
  #
@@ -87,7 +83,10 @@ module Nmap
87
83
  # @since 0.7.0
88
84
  #
89
85
  def self.open(path,&block)
90
- new(path,&block)
86
+ path = File.expand_path(path)
87
+ doc = Nokogiri::XML(File.open(path))
88
+
89
+ new(doc, path: path, &block)
91
90
  end
92
91
 
93
92
  #
@@ -270,8 +269,6 @@ module Nmap
270
269
  end
271
270
  end
272
271
 
273
- alias prescripts prescript
274
-
275
272
  #
276
273
  # The NSE scripts ran after the scan.
277
274
  #
@@ -286,8 +283,6 @@ module Nmap
286
283
  end
287
284
  end
288
285
 
289
- alias postscripts postscript
290
-
291
286
  #
292
287
  # Parses the hosts in the scan.
293
288
  #
@@ -437,20 +432,12 @@ module Nmap
437
432
  # Converts the XML parser to a String.
438
433
  #
439
434
  # @return [String]
440
- # The path of the XML scan file.
435
+ # The path of the XML file or the raw XML.
441
436
  #
442
437
  def to_s
443
- @path.to_s
444
- end
445
-
446
- #
447
- # Inspects the XML file.
448
- #
449
- # @return [String]
450
- # The inspected XML file.
451
- #
452
- def inspect
453
- "#<#{self.class}: #{self}>"
438
+ if @path then @path.to_s
439
+ else @doc.to_s
440
+ end
454
441
  end
455
442
 
456
443
  end