Object
This library provides a Ruby interface to Nmap's scan data. It can run Nmap and parse its XML output directly from the scan, parse a file containing the XML data from a separate scan, parse a String of XML data from a scan, or parse XML data from an object via its read() method. This information is presented in an easy-to-use and intuitive fashion for storage and manipulation.
Keep in mind that this is not just some Ruby port of Anthony Persaud's Perl Nmap::Parser! There are more classes, many different methods, and blocks are extensively available.
The Nmap Security Scanner is an awesome program written and maintained by Fyodor <fyodor@insecure.org>. Its main function is port scanning, but it also has service and operating system detection, its own scripting engine and a whole lot more. One of its many available output formats is XML, which allows machines to handle all of the information instead of us slowly sifting through tons of output.
Depending on the data type, unavailable information is presented differently:
- Arrays are empty - Non-arrays are nil, unless it's a method that returns the size of one of the previously mentioned empty arrays. In this case they still return the size (which would be 0).
All information available as arrays are presented via methods. These methods not only return the array, but they also yield each element to a block if one is given.
Nmap::Parser | + Session <- Scan session information | + Host <- General host information | + ExtraPorts <- Ports consolidated in an "ignored" state | + Port <- General port information | | | + Service <- Port Service information | + Script <- NSE Script information (both host and port) | + Times <- Timimg information (round-trip time, etc) | + Traceroute <- General Traceroute information | | | + Hop <- Individual Hop information | + OS <- OS Detection information | + OSClass <- OS Class information | + OSMatch <- OS Match information
require 'nmap/parser' parser = Nmap::Parser.parsestring(xml) # String of XML parser = Nmap::Parser.new(xml) # Same thing
require 'nmap/parser' parser = Nmap::Parser.parsefile("log.xml")
This method can read from any object that responds to a read() method that returns a String.
require 'nmap/parser' parser = Nmap::Parser.parseread($stdin)
This is the only Parser method that requires Nmap to be available.
require 'nmap/parser' parser = Nmap::Parser.parsescan("sudo nmap", "-sVC 192.168.1.0/24")
After printing a little session information, this example will cycle through all of the up hosts, printing state and service information on the open TCP ports. See the examples directory that comes with this library for more examples.
puts "Nmap args: #{parser.session.scan_args}" puts "Runtime: #{parser.session.scan_time} seconds" puts parser.hosts("up") do |host| puts "#{host.addr} is up:" puts host.tcp_ports("open") do |port| srv = port.service puts "Port ##{port.num}/tcp is open (#{port.reason})" puts "\tService: #{srv.name}" if srv.name puts "\tProduct: #{srv.product}" if srv.product puts "\tVersion: #{srv.version}" if srv.version puts end puts end
# File lib/nmap/parser.rb, line 319 def initialize(xml) # :yields: parser if not xml.is_a?(String) raise "Must be passed a String (got #{xml.class})" end parse(xml) yield self if block_given? end
Read and parse the contents of the Nmap XML file filename
Returns a new Nmap::Parser object, and passes it to a block if one is given
# File lib/nmap/parser.rb, line 192 def self.parsefile(filename) # :yields: parser begin File.open(filename) { |f| parseread(f) { |p| yield p if block_given? } } rescue raise "Error parsing \"#{filename}\": #{$!}" end end
Read and parse XML from the obj. obj can be any object type that responds to a read() method that returns a String. IO and File are just a couple of examples.
Returns a new Nmap::Parser object, and passes it to a block if one is given
# File lib/nmap/parser.rb, line 174 def self.parseread(obj) # :yields: parser if not obj.respond_to?("read") raise "Passed object must respond to read()" end r = obj.read if not r.is_a?(String) raise "Passed object's read() must return a String (got #{r.class})" end new(r) { |p| yield p if block_given? } end
Runs "nmap -d args targets"; returns a new Nmap::Parser object, and passes it to a block if one is given.
nmap is here to allow you to do things like:
parser = Nmap::Parser.parsescan("sudo ./nmap", ....)
and still make it easy for me to inject the options for XML output and debugging.
args can't contain arguments like -oA, -oX, etc. as these can interfere with Parser's processing. If you need that other output, just run Nmap yourself and pass -oX output to Parser via new. Or, you can use rawxml to grab the whole XML (as a String) and save it to a different file.
targets is an array of targets which will be split and appended to the command. It's optional and only for convenience because you can put any targets you want scanned in args.
# File lib/nmap/parser.rb, line 229 def self.parsescan(nmap, args, targets = []) # :yields: parser if args =~ /[^-]-o|^-o/ raise "Output option (-o*) passed to parsescan()" end # Enable debugging, give us our XML output, pass args command = nmap + " -d -oX - " + args + " " command += targets.join(" ") if targets.any? p = nil begin # First try popen3() if it loaded successfully.. Open3.popen3(command) do |sin, sout, serr| p = parseread(sout) end rescue NameError # ..but fall back to popen() if not IO.popen(command) do |io| p = parseread(io) end end yield p if block_given? p end
Read and parse the String of XML. Currently an alias for new().
Returns a new Nmap::Parser object, and passes it to a block if one is given
# File lib/nmap/parser.rb, line 206 def self.parsestring(str) # :yields: parser new(str) { |p| yield p if block_given? } end
This operator compares the rawxml members
# File lib/nmap/parser.rb, line 313 def ==(parser) @rawxml == parser.rawxml end
Deletes host with the specified IP address or hostname hostip
Note: From inside of a block given to a method like hosts() or get_ips(), calling this method on a host passed to the block may lead to adverse effects:
parser.hosts { |h| puts h.addr; parser.del_host(h) } # Don't do this!
# File lib/nmap/parser.rb, line 292 def del_host(hostip) @hosts.delete_if do |host| host.addr == hostip or host.hostname == hostip end end
Returns an array of IPs scanned, and passes them each to a block if one is given
If an argument is given, only hosts matching status are given
# File lib/nmap/parser.rb, line 304 def get_ips(status = "") # :yields: host.addr ips = hosts(status).map { |h| h.addr } ips.each { |ip| yield host.addr } if block_given? ips end
Returns a Host object for the host with the specified IP address or hostname hostip
# File lib/nmap/parser.rb, line 277 def host(hostip) @hosts.find do |host| host.addr == hostip or host.hostname == hostip end end
Returns an array of Host objects, and passes them each to a block if one is given
If an argument is given, only hosts matching status are given
# File lib/nmap/parser.rb, line 262 def hosts(status = "") # :yields: host shosts = [] @hosts.each do |host| if status.empty? or host.status == status shosts << host yield host if block_given? end end shosts end
Generated with the Darkfish Rdoc Generator 2.