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.
- checksums.yaml +4 -4
- data/.document +1 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/ChangeLog.md +118 -71
- data/Gemfile +11 -5
- data/LICENSE.txt +1 -1
- data/README.md +88 -50
- data/Rakefile +5 -0
- data/UPGRADING.md +47 -0
- data/gemspec.yml +5 -5
- data/lib/nmap/command.rb +765 -0
- data/lib/nmap/version.rb +1 -1
- data/lib/nmap/xml/address.rb +38 -0
- data/lib/nmap/xml/cpe/url.rb +80 -0
- data/lib/nmap/xml/cpe.rb +47 -0
- data/lib/nmap/xml/hop.rb +22 -0
- data/lib/nmap/xml/host.rb +546 -0
- data/lib/nmap/xml/host_script.rb +26 -0
- data/lib/nmap/xml/hostname.rb +44 -0
- data/lib/nmap/xml/ip_id_sequence.rb +26 -0
- data/lib/nmap/xml/os.rb +131 -0
- data/lib/nmap/xml/os_class.rb +86 -0
- data/lib/nmap/xml/os_match.rb +22 -0
- data/lib/nmap/xml/port.rb +114 -0
- data/lib/nmap/xml/postscript.rb +26 -0
- data/lib/nmap/xml/prescript.rb +26 -0
- data/lib/nmap/xml/run_stat.rb +22 -0
- data/lib/nmap/xml/scan.rb +38 -0
- data/lib/nmap/xml/scan_task.rb +55 -0
- data/lib/nmap/xml/scanner.rb +22 -0
- data/lib/nmap/xml/script.rb +110 -0
- data/lib/nmap/xml/scripts.rb +33 -0
- data/lib/nmap/xml/sequence.rb +52 -0
- data/lib/nmap/xml/service.rb +172 -0
- data/lib/nmap/xml/status.rb +22 -0
- data/lib/nmap/xml/tcp_sequence.rb +48 -0
- data/lib/nmap/xml/tcp_ts_sequence.rb +26 -0
- data/lib/nmap/xml/traceroute.rb +73 -0
- data/lib/nmap/xml/uptime.rb +22 -0
- data/lib/nmap/xml.rb +31 -44
- data/spec/command_spec.rb +726 -0
- data/spec/fixtures/down_host_scan.xml +16 -0
- data/spec/{address_spec.rb → xml/address_spec.rb} +2 -2
- data/spec/{cpe → xml/cpe}/url_spec.rb +1 -1
- data/spec/{cpe_examples.rb → xml/cpe_examples.rb} +1 -1
- data/spec/{hop_spec.rb → xml/hop_spec.rb} +2 -2
- data/spec/{host_script_spec.rb → xml/host_script_spec.rb} +2 -2
- data/spec/{host_spec.rb → xml/host_spec.rb} +8 -8
- data/spec/{hostname_spec.rb → xml/hostname_spec.rb} +2 -2
- data/spec/{ip_id_sequence_spec.rb → xml/ip_id_sequence_spec.rb} +3 -3
- data/spec/{os_class_spec.rb → xml/os_class_spec.rb} +3 -3
- data/spec/{os_match_spec.rb → xml/os_match_spec.rb} +2 -2
- data/spec/{os_spec.rb → xml/os_spec.rb} +3 -3
- data/spec/{port_spec.rb → xml/port_spec.rb} +4 -5
- data/spec/{postscript_spec.rb → xml/postscript_spec.rb} +2 -2
- data/spec/{prescript_spec.rb → xml/prescript_spec.rb} +2 -2
- data/spec/{run_stat_spec.rb → xml/run_stat_spec.rb} +2 -2
- data/spec/{scan_spec.rb → xml/scan_spec.rb} +2 -2
- data/spec/{scan_task_spec.rb → xml/scan_task_spec.rb} +6 -6
- data/spec/{scanner_spec.rb → xml/scanner_spec.rb} +3 -3
- data/spec/xml/script_spec.rb +137 -0
- data/spec/xml/scripts_examples.rb +19 -0
- data/spec/{sequence_examples.rb → xml/sequence_examples.rb} +1 -0
- data/spec/{service_spec.rb → xml/service_spec.rb} +31 -5
- data/spec/{status_spec.rb → xml/status_spec.rb} +2 -2
- data/spec/{tcp_sequence_spec.rb → xml/tcp_sequence_spec.rb} +3 -3
- data/spec/{tcp_ts_sequence_spec.rb → xml/tcp_ts_sequence_spec.rb} +3 -3
- data/spec/{traceroute_spec.rb → xml/traceroute_spec.rb} +3 -3
- data/spec/{uptime_spec.rb → xml/uptime_spec.rb} +2 -2
- data/spec/xml_spec.rb +73 -44
- metadata +72 -66
- data/.travis.yml +0 -16
- data/lib/nmap/address.rb +0 -34
- data/lib/nmap/cpe/url.rb +0 -78
- data/lib/nmap/cpe.rb +0 -45
- data/lib/nmap/hop.rb +0 -20
- data/lib/nmap/host.rb +0 -587
- data/lib/nmap/host_script.rb +0 -18
- data/lib/nmap/hostname.rb +0 -42
- data/lib/nmap/ip_id_sequence.rb +0 -24
- data/lib/nmap/os.rb +0 -127
- data/lib/nmap/os_class.rb +0 -82
- data/lib/nmap/os_match.rb +0 -18
- data/lib/nmap/port.rb +0 -110
- data/lib/nmap/postscript.rb +0 -16
- data/lib/nmap/prescript.rb +0 -16
- data/lib/nmap/program.rb +0 -102
- data/lib/nmap/run_stat.rb +0 -20
- data/lib/nmap/scan.rb +0 -34
- data/lib/nmap/scan_task.rb +0 -53
- data/lib/nmap/scanner.rb +0 -18
- data/lib/nmap/scripts.rb +0 -71
- data/lib/nmap/sequence.rb +0 -50
- data/lib/nmap/service.rb +0 -170
- data/lib/nmap/status.rb +0 -18
- data/lib/nmap/task.rb +0 -387
- data/lib/nmap/tcp_sequence.rb +0 -46
- data/lib/nmap/tcp_ts_sequence.rb +0 -22
- data/lib/nmap/traceroute.rb +0 -71
- data/lib/nmap/uptime.rb +0 -20
- data/spec/scripts_examples.rb +0 -35
- data/spec/task_spec.rb +0 -150
data/lib/nmap/xml/os.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'nmap/xml/os_class'
|
2
|
+
require 'nmap/xml/os_match'
|
3
|
+
|
4
|
+
module Nmap
|
5
|
+
class XML
|
6
|
+
#
|
7
|
+
# Wraps the `os` XML element.
|
8
|
+
#
|
9
|
+
# @since 1.0.0
|
10
|
+
#
|
11
|
+
class OS
|
12
|
+
|
13
|
+
include Enumerable
|
14
|
+
|
15
|
+
#
|
16
|
+
# Creates a new OS object.
|
17
|
+
#
|
18
|
+
# @param [Nokogiri::XML::Node] node
|
19
|
+
# The node that contains the OS guessing information.
|
20
|
+
#
|
21
|
+
def initialize(node)
|
22
|
+
@node = node
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Parses the OS class information.
|
27
|
+
#
|
28
|
+
# @yield [class]
|
29
|
+
# Passes each OS class to the given block.
|
30
|
+
#
|
31
|
+
# @yieldparam [OSClass] class
|
32
|
+
# The OS class information.
|
33
|
+
#
|
34
|
+
# @return [OS, Enumerator]
|
35
|
+
# The OS information. If no block was given, an enumerator object
|
36
|
+
# will be returned.
|
37
|
+
#
|
38
|
+
def each_class
|
39
|
+
return enum_for(__method__) unless block_given?
|
40
|
+
|
41
|
+
@node.xpath("osmatch/osclass").each do |osclass|
|
42
|
+
yield OSClass.new(osclass)
|
43
|
+
end
|
44
|
+
|
45
|
+
return self
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Parses the OS class information.
|
50
|
+
#
|
51
|
+
# @return [Array<OSClass>]
|
52
|
+
# The OS class information.
|
53
|
+
#
|
54
|
+
def classes
|
55
|
+
each_class.to_a
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Parses the OS match information.
|
60
|
+
#
|
61
|
+
# @yield [match]
|
62
|
+
# Passes each OS match to the given block.
|
63
|
+
#
|
64
|
+
# @yieldparam [OSMatch] class
|
65
|
+
# The OS match information.
|
66
|
+
#
|
67
|
+
# @return [OS, Enumerator]
|
68
|
+
# The OS information. If no block was given, an enumerator object
|
69
|
+
# will be returned.
|
70
|
+
#
|
71
|
+
def each_match
|
72
|
+
return enum_for(__method__) unless block_given?
|
73
|
+
|
74
|
+
@node.xpath("osmatch").map do |osclass|
|
75
|
+
os_match = OSMatch.new(
|
76
|
+
osclass['name'],
|
77
|
+
osclass['accuracy'].to_i
|
78
|
+
)
|
79
|
+
|
80
|
+
yield os_match
|
81
|
+
end
|
82
|
+
|
83
|
+
return self
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Parses the OS match information.
|
88
|
+
#
|
89
|
+
# @return [Array<OSMatch>]
|
90
|
+
# The OS match information.
|
91
|
+
#
|
92
|
+
def matches
|
93
|
+
each_match.to_a
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Parses the ports used for guessing the OS.
|
98
|
+
#
|
99
|
+
# @return [Array<Integer>]
|
100
|
+
# The ports used.
|
101
|
+
#
|
102
|
+
def ports_used
|
103
|
+
@ports_used ||= @node.xpath("portused/@portid").map do |port|
|
104
|
+
port.inner_text.to_i
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Parses the OS fingerprint used by Nmap.
|
110
|
+
#
|
111
|
+
# @return [String]
|
112
|
+
# The OS fingerprint.
|
113
|
+
#
|
114
|
+
def fingerprint
|
115
|
+
@fingerprint ||= if (fingerprint = @node.at_xpath("osfingerprint/@fingerprint"))
|
116
|
+
fingerprint.inner_text
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Parses the OS match information.
|
122
|
+
#
|
123
|
+
# @see #each_match
|
124
|
+
#
|
125
|
+
def each(&block)
|
126
|
+
each_match(&block)
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'nmap/xml/cpe'
|
2
|
+
|
3
|
+
module Nmap
|
4
|
+
class XML
|
5
|
+
#
|
6
|
+
# Represents an {OS} class.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
#
|
10
|
+
class OSClass
|
11
|
+
|
12
|
+
include CPE
|
13
|
+
|
14
|
+
#
|
15
|
+
# Initializes the OS.
|
16
|
+
#
|
17
|
+
# @param [Nokogiri::XML::Node] node
|
18
|
+
# The node that contains the OS Class information.
|
19
|
+
#
|
20
|
+
def initialize(node)
|
21
|
+
@node = node
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# The OS type.
|
26
|
+
#
|
27
|
+
# @return [String]
|
28
|
+
#
|
29
|
+
def type
|
30
|
+
@type ||= if @node['type']
|
31
|
+
@node['type'].to_sym
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# The OS vendor.
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
#
|
40
|
+
def vendor
|
41
|
+
@vendor ||= @node.get_attribute('vendor')
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# The OS family.
|
46
|
+
#
|
47
|
+
# @return [Symbol, nil]
|
48
|
+
#
|
49
|
+
def family
|
50
|
+
@family ||= @node.get_attribute('osfamily').to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# The OS generation.
|
55
|
+
#
|
56
|
+
# @return [Symbol, nil]
|
57
|
+
#
|
58
|
+
def gen
|
59
|
+
@gen ||= if @node['osgen']
|
60
|
+
@node['osgen'].to_sym
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# The accuracy of the OS class information.
|
66
|
+
#
|
67
|
+
# @return [Integer]
|
68
|
+
# Returns a number between 0 and 10.
|
69
|
+
#
|
70
|
+
def accuracy
|
71
|
+
@accuracy ||= @node.get_attribute('accuracy').to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Converts the OS class to a String.
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
# The String form of the OS class.
|
79
|
+
#
|
80
|
+
def to_s
|
81
|
+
"#{self.type} #{self.vendor} (#{self.accuracy}%)"
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# Represents a match for a specific {OS}.
|
5
|
+
#
|
6
|
+
# @since 1.0.0
|
7
|
+
#
|
8
|
+
class OSMatch < Struct.new(:name, :accuracy)
|
9
|
+
|
10
|
+
#
|
11
|
+
# Converts the OS match to a String.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
# The String form of the OS match.
|
15
|
+
#
|
16
|
+
def to_s
|
17
|
+
"#{self.name} (#{self.accuracy}%)"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'nmap/xml/service'
|
2
|
+
require 'nmap/xml/scripts'
|
3
|
+
|
4
|
+
module Nmap
|
5
|
+
class XML
|
6
|
+
#
|
7
|
+
# Wraps a `port` XML element.
|
8
|
+
#
|
9
|
+
# @since 1.0.0
|
10
|
+
#
|
11
|
+
class Port
|
12
|
+
|
13
|
+
include Scripts
|
14
|
+
|
15
|
+
#
|
16
|
+
# Creates a new Port object.
|
17
|
+
#
|
18
|
+
# @param [Nokogiri::XML::Element] node
|
19
|
+
# The XML `port` element.
|
20
|
+
#
|
21
|
+
def initialize(node)
|
22
|
+
@node = node
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# The protocol the port runs on
|
27
|
+
#
|
28
|
+
# @return [Symbol]
|
29
|
+
# The protocol of the port.
|
30
|
+
#
|
31
|
+
def protocol
|
32
|
+
@protocol ||= @node['protocol'].to_sym
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# The port number.
|
37
|
+
#
|
38
|
+
# @return [Integer]
|
39
|
+
# The number of the port.
|
40
|
+
#
|
41
|
+
def number
|
42
|
+
@number ||= @node['portid'].to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# The state of the port.
|
47
|
+
#
|
48
|
+
# @return [Symbol]
|
49
|
+
# The state of the port (`:open`, `:filtered` or `:closed`).
|
50
|
+
#
|
51
|
+
def state
|
52
|
+
@state ||= @node.at_xpath('state/@state').inner_text.to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# The reason the port was discovered.
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
# How the port was discovered.
|
60
|
+
#
|
61
|
+
def reason
|
62
|
+
@reason ||= @node.at_xpath('state/@reason').inner_text
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# The reason TTL.
|
67
|
+
#
|
68
|
+
# @return [Integer]
|
69
|
+
#
|
70
|
+
# @since 0.10.0
|
71
|
+
#
|
72
|
+
def reason_ttl
|
73
|
+
@reason ||= @node.at_xpath('state/@reason_ttl').inner_text.to_i
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# The fingerprinted service of the port.
|
78
|
+
#
|
79
|
+
# @return [Service]
|
80
|
+
# The service detected on the port.
|
81
|
+
#
|
82
|
+
# @since 0.6.0
|
83
|
+
#
|
84
|
+
def service
|
85
|
+
@service_info ||= if (service = @node.at_xpath('service'))
|
86
|
+
Service.new(service)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
alias to_i number
|
91
|
+
|
92
|
+
#
|
93
|
+
# Converts the port to a String.
|
94
|
+
#
|
95
|
+
# @return [String]
|
96
|
+
# The port number.
|
97
|
+
#
|
98
|
+
def to_s
|
99
|
+
number.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Inspects the port.
|
104
|
+
#
|
105
|
+
# @return [String]
|
106
|
+
# The inspected port.
|
107
|
+
#
|
108
|
+
def inspect
|
109
|
+
"#<#{self.class}: #{self}>"
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'nmap/xml/scripts'
|
2
|
+
|
3
|
+
module Nmap
|
4
|
+
class XML
|
5
|
+
#
|
6
|
+
# Represents the `postscript` element.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
#
|
10
|
+
class Postscript
|
11
|
+
|
12
|
+
include Scripts
|
13
|
+
|
14
|
+
#
|
15
|
+
# Initializes the Postscript 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,26 @@
|
|
1
|
+
require 'nmap/xml/scripts'
|
2
|
+
|
3
|
+
module Nmap
|
4
|
+
class XML
|
5
|
+
#
|
6
|
+
# Represents the `prescript` element.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
#
|
10
|
+
class Prescript
|
11
|
+
|
12
|
+
include Scripts
|
13
|
+
|
14
|
+
#
|
15
|
+
# Initializes the Prescript 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,22 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# Represents the runstats of a scan.
|
5
|
+
#
|
6
|
+
# @since 1.0.0
|
7
|
+
#
|
8
|
+
class RunStat < Struct.new(:end_time, :elapsed, :summary, :exit_status)
|
9
|
+
|
10
|
+
#
|
11
|
+
# Converts the stats to a String.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
# The String form of the scan.
|
15
|
+
#
|
16
|
+
def to_s
|
17
|
+
"#{self.end_time} #{self.elapsed} #{self.exit_status}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# Represents an Nmap scan.
|
5
|
+
#
|
6
|
+
# @since 1.0.0
|
7
|
+
#
|
8
|
+
class Scan < Struct.new(:type, :protocol, :services)
|
9
|
+
|
10
|
+
#
|
11
|
+
# Creates a new Scan object.
|
12
|
+
#
|
13
|
+
# @param [Symbol] type
|
14
|
+
# The type of the scan.
|
15
|
+
#
|
16
|
+
# @param [Symbol] protocol
|
17
|
+
# The protocol used for the scan.
|
18
|
+
#
|
19
|
+
# @param [Array<Integer, Rage>] services
|
20
|
+
# The port numbers scanned.
|
21
|
+
#
|
22
|
+
def initialize(type,protocol,services=[])
|
23
|
+
super(type,protocol,services)
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Converts the scan to a String.
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
# The String form of the scan.
|
31
|
+
#
|
32
|
+
def to_s
|
33
|
+
"#{self.protocol} #{self.type}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# @since 1.0.0
|
5
|
+
#
|
6
|
+
class ScanTask < Struct.new(:name, :start_time, :end_time, :extra_info)
|
7
|
+
|
8
|
+
#
|
9
|
+
# Creates a new ScanTask object.
|
10
|
+
#
|
11
|
+
# @param [String] name
|
12
|
+
# The name of the scan task.
|
13
|
+
#
|
14
|
+
# @param [Time] start_time
|
15
|
+
# The time the scan task begun.
|
16
|
+
#
|
17
|
+
# @param [Time] end_time
|
18
|
+
# The time the scan task ended.
|
19
|
+
#
|
20
|
+
# @param [String] extra_info
|
21
|
+
# Any extra information relating to the scan task.
|
22
|
+
#
|
23
|
+
# @since 0.1.2
|
24
|
+
#
|
25
|
+
def initialize(name,start_time,end_time,extra_info=nil)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# The duration of the scan task.
|
31
|
+
#
|
32
|
+
# @return [Integer]
|
33
|
+
# The number of seconds it took the scan task to complete.
|
34
|
+
#
|
35
|
+
# @since 0.1.2
|
36
|
+
#
|
37
|
+
def duration
|
38
|
+
(self.end_time - self.start_time)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Converts the scan task to a String.
|
43
|
+
#
|
44
|
+
# @return [String]
|
45
|
+
# The String form of the scan task.
|
46
|
+
#
|
47
|
+
# @since 0.1.2
|
48
|
+
#
|
49
|
+
def to_s
|
50
|
+
"#{self.start_time}: #{self.name} (#{self.extra_info})"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# Describes the `nmap` command.
|
5
|
+
#
|
6
|
+
# @since 1.0.0
|
7
|
+
#
|
8
|
+
class Scanner < Struct.new(:name, :version, :arguments, :start_time)
|
9
|
+
|
10
|
+
#
|
11
|
+
# Converts the scanner to a String.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
# The scanner name and arguments.
|
15
|
+
#
|
16
|
+
def to_s
|
17
|
+
"#{self.name} #{self.arguments}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Nmap
|
2
|
+
class XML
|
3
|
+
#
|
4
|
+
# Wraps a `script` XML element.
|
5
|
+
#
|
6
|
+
# @since 1.0.0
|
7
|
+
#
|
8
|
+
class Script
|
9
|
+
|
10
|
+
#
|
11
|
+
# Initializes a new Script object.
|
12
|
+
#
|
13
|
+
# @param [Nokogiri::XML::Node] node
|
14
|
+
# The XML node that contains the host information.
|
15
|
+
#
|
16
|
+
def initialize(node)
|
17
|
+
@node = node
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# The ID of the NSE script.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
#
|
25
|
+
def id
|
26
|
+
@id ||= @node['id']
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# The text output from the NSE script.
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
#
|
34
|
+
def output
|
35
|
+
@output ||= @node['output']
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Parses the structured data within the `<script>` XML element.
|
40
|
+
#
|
41
|
+
# @return [Hash{String => Hash,Array,String}, Array<Hash>, Array<String>, nil]
|
42
|
+
# The parsed data.
|
43
|
+
#
|
44
|
+
def data
|
45
|
+
@data ||= parse_table(@node)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
#
|
51
|
+
# Parses the `<table>` XML child elements within the given node.
|
52
|
+
#
|
53
|
+
# @param [Nokogiri::XML::Node] node
|
54
|
+
# The XML node that contains the host information.
|
55
|
+
#
|
56
|
+
# @return [Hash{String => Hash,Array,String}, Array<Hash>, Array<String>, nil]
|
57
|
+
# The parsed data.
|
58
|
+
#
|
59
|
+
def parse_tables(node)
|
60
|
+
if (tables = @node.xpath('table')).empty?
|
61
|
+
return
|
62
|
+
end
|
63
|
+
|
64
|
+
# check for named tables
|
65
|
+
if tables.all? { |table| table.has_attribute?('key') }
|
66
|
+
Hash[
|
67
|
+
tables.map { |table|
|
68
|
+
[table['key'], parse_table(table)]
|
69
|
+
}
|
70
|
+
]
|
71
|
+
else
|
72
|
+
tables.map(&method(:parse_table))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Parses the contents of a `<table>` XML element.
|
78
|
+
#
|
79
|
+
# @param [Nokogiri::XML::Node] node
|
80
|
+
# The XML node that contains the host information.
|
81
|
+
#
|
82
|
+
# @return [Hash{String => Hash,Array<String>,String}, Array<String>, nil]
|
83
|
+
# The parsed data.
|
84
|
+
#
|
85
|
+
def parse_table(node)
|
86
|
+
# check for nested tables
|
87
|
+
if node.xpath('count(table)') > 0
|
88
|
+
return parse_tables(node)
|
89
|
+
end
|
90
|
+
|
91
|
+
if (elems = node.xpath('elem')).empty?
|
92
|
+
# return nil if there are no elements
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
# check for named elements
|
97
|
+
if elems.all? { |elem| elem.has_attribute?('key') }
|
98
|
+
Hash[
|
99
|
+
elems.map { |elem|
|
100
|
+
[elem['key'], elem.inner_text]
|
101
|
+
}
|
102
|
+
]
|
103
|
+
else
|
104
|
+
elems.map(&:inner_text)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'nmap/xml/script'
|
2
|
+
|
3
|
+
module Nmap
|
4
|
+
class XML
|
5
|
+
#
|
6
|
+
# Mixin that adds methods for parsing `<script>` XML elements.
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
#
|
10
|
+
module Scripts
|
11
|
+
#
|
12
|
+
# The output from the NSE script's output and structured data.
|
13
|
+
#
|
14
|
+
# @return [Hash{String => Script}]
|
15
|
+
# The NSE script names and output.
|
16
|
+
#
|
17
|
+
# @since 0.3.0
|
18
|
+
#
|
19
|
+
def scripts
|
20
|
+
unless @scripts
|
21
|
+
@scripts = {}
|
22
|
+
|
23
|
+
@node.xpath('script').each do |script|
|
24
|
+
@scripts[script['id']] = Script.new(script)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
return @scripts
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|