diff --git a/lib/nmap/xml/os.rb b/lib/nmap/xml/os.rb index 2e1ff2b..51693bc 100644 --- a/lib/nmap/xml/os.rb +++ b/lib/nmap/xml/os.rb @@ -2,6 +2,7 @@ require_relative 'os_class' require_relative 'os_match' +require_relative 'port_used' module Nmap class XML @@ -93,12 +94,16 @@ def matches # # Parses the ports used for guessing the OS. # - # @return [Array] + # @return [Array] # The ports used. # def ports_used - @ports_used ||= @node.xpath("portused/@portid").map do |port| - port.inner_text.to_i + @ports_used ||= @node.xpath("portused").map do |portused| + PortUsed.new( + portused['state'].to_sym, + portused['proto'].to_sym, + portused['portid'].to_i + ) end end diff --git a/lib/nmap/xml/port_used.rb b/lib/nmap/xml/port_used.rb new file mode 100644 index 0000000..4990530 --- /dev/null +++ b/lib/nmap/xml/port_used.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Nmap + class XML + # + # Represents a port used to perform OS fingerprinting. + # + # @since 1.1.0 + # + class PortUsed < Struct.new(:state,:protocol,:port) + + alias to_i port + alias to_int port + + end + end +end diff --git a/spec/xml/os_spec.rb b/spec/xml/os_spec.rb index 4a37b23..35f4cb1 100644 --- a/spec/xml/os_spec.rb +++ b/spec/xml/os_spec.rb @@ -32,7 +32,10 @@ subject { super().ports_used } it { expect(subject).not_to be_empty } - it { expect(subject).to all(be_between(0,65535)) } + it { expect(subject).to all(be_kind_of(Nmap::XML::PortUsed)) } + it { expect(subject.map(&:state)).to all(eq(:open).or(eq(:closed))) } + it { expect(subject.map(&:protocol)).to all(eq(:tcp).or(eq(:udp))) } + it { expect(subject.map(&:port)).to all(be_between(0,65535)) } end describe "#fingerprint" do diff --git a/spec/xml/port_used_spec.rb b/spec/xml/port_used_spec.rb new file mode 100644 index 0000000..b077e7b --- /dev/null +++ b/spec/xml/port_used_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' +require 'nmap/xml/port_used' + +describe Nmap::XML::PortUsed do + let(:state) { :open } + let(:protocol) { :tcp } + let(:port) { 22 } + + subject { described_class.new(state,protocol,port) } + + describe "#to_i" do + it "must return the port number" do + expect(subject.to_i).to eq(port) + end + end + + describe "#to_int" do + it "must return the port number" do + expect(subject.to_int).to eq(port) + end + end +end