From d839f218bf4f628f5b5247fa02468341f92959ca Mon Sep 17 00:00:00 2001 From: Anirudh Gupta Date: Tue, 3 May 2016 14:30:59 +0530 Subject: [PATCH] hpux support for basic port properties --- lib/resources/port.rb | 51 ++++++++++++++++++++++++++++++-- test/helper.rb | 6 +++- test/unit/mock/cmd/netstat-inet | 10 +++++++ test/unit/mock/cmd/netstat-inet6 | 11 +++++++ test/unit/resources/port_test.rb | 14 +++++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 test/unit/mock/cmd/netstat-inet create mode 100644 test/unit/mock/cmd/netstat-inet6 diff --git a/lib/resources/port.rb b/lib/resources/port.rb index fc8978770..767fc85f9 100644 --- a/lib/resources/port.rb +++ b/lib/resources/port.rb @@ -3,7 +3,7 @@ # author: Dominik Richter require 'utils/parser' - +require 'pry' # Usage: # describe port(80) do # it { should be_listening } @@ -47,6 +47,8 @@ module Inspec::Resources @port_manager = FreeBsdPorts.new(inspec) elsif os.solaris? @port_manager = SolarisPorts.new(inspec) + elsif os.hpux? + @port_manager = HpuxPorts.new(inspec) else return skip_resource 'The `port` resource is not supported on your OS yet.' end @@ -292,7 +294,6 @@ module Inspec::Resources # parse each line # 1 - Proto, 2 - Recv-Q, 3 - Send-Q, 4 - Local Address, 5 - Foreign Address, 6 - State, 7 - Inode, 8 - PID/Program name parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?\s+(\S+)\s+(\S+)\s+(\S+)/.match(line) - return {} if parsed.nil? || line.match(/^proto/i) # parse ip4 and ip6 addresses @@ -408,7 +409,7 @@ module Inspec::Resources # parse the content netstat_ports = parse_netstat(cmd.stdout) - # filter all ports, where we listen + # filter all ports, where we `listen` listen = netstat_ports.select { |val| !val['state'].nil? && 'listen'.casecmp(val['state']) == 0 } @@ -433,4 +434,48 @@ module Inspec::Resources ports end end + + # extracts information from netstat for hpux + class HpuxPorts < FreeBsdPorts + def info + ## Can't use 'netstat -an -f inet -f inet6' as the latter -f option overrides the former one and return only inet ports + cmd1 = inspec.command('netstat -an -f inet') + return nil if cmd1.exit_status.to_i != 0 + cmd2 = inspec.command('netstat -an -f inet6') + return nil if cmd2.exit_status.to_i != 0 + cmd = cmd1.stdout + cmd2.stdout + ports = [] + # parse all lines + cmd.each_line do |line| + port_info = parse_netstat_line(line) + next unless %w{tcp tcp6 udp udp6}.include?(port_info[:protocol]) + ports.push(port_info) + end + # select all ports, where we `listen` + ports.select { |val| val if 'listen'.casecmp(val[:state]) == 0 } + end + + def parse_netstat_line(line) + # parse each line + # 1 - Proto, 2 - Recv-Q, 3 - Send-Q, 4 - Local Address, 5 - Foreign Address, 6 - (state) + parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?/.match(line) + + return {} if parsed.nil? || line.match(/^proto/i) || line.match(/^active/i) + protocol = parsed[1].downcase + state = parsed[6].nil?? ' ' : parsed[6].downcase + local_addr = parsed[4] + local_addr[local_addr.rindex('.')] = ':' + # extract host and port information + host, port = parse_net_address(local_addr, protocol) + # map data + { + port: port, + address: host, + protocol: protocol, + state: state, + process: nil, + pid: nil, + } + end + end end diff --git a/test/helper.rb b/test/helper.rb index 867a0285b..23e5e3da3 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -246,7 +246,11 @@ class MockLoader #user info on hpux "logins -x -l root" => cmd.call('logins-x'), #packages on hpux - "swlist -l product | grep vim" => cmd.call('swlist-l-product') + "swlist -l product | grep vim" => cmd.call('swlist-l-product'), + # ipv4 ports on hpux + 'netstat -an -f inet' => cmd.call('netstat-inet'), + #ipv6 ports on hpux + 'netstat -an -f inet6' => cmd.call('netstat-inet6'), } @backend diff --git a/test/unit/mock/cmd/netstat-inet b/test/unit/mock/cmd/netstat-inet new file mode 100644 index 000000000..c6713c0d7 --- /dev/null +++ b/test/unit/mock/cmd/netstat-inet @@ -0,0 +1,10 @@ +Active Internet connections (including servers) +Proto Recv-Q Send-Q Local Address Foreign Address (state) +tcp 0 0 *.515 *.* LISTEN +tcp 0 28 16.147.37.141.22 16.180.154.172.64145 ESTABLISHED +tcp 0 0 *.22 *.* LISTEN +tcp 0 0 *.49196 *.* LISTEN +tcp 0 0 16.147.37.141.49399 16.147.37.141.1712 ESTABLISHED +tcp 0 0 127.0.0.1.49433 *.* LISTEN +udp 0 0 127.0.0.1.49178 127.0.0.1.49178 +udp 0 0 *.49153 *.* diff --git a/test/unit/mock/cmd/netstat-inet6 b/test/unit/mock/cmd/netstat-inet6 new file mode 100644 index 000000000..2a3852691 --- /dev/null +++ b/test/unit/mock/cmd/netstat-inet6 @@ -0,0 +1,11 @@ +Active Internet connections (IPv6, including servers) +Proto Recv-Q Send-Q Local Address Foreign Address (state) +tcp6 0 0 ::1.49309 *.* LISTEN +tcp6 0 0 *.21 *.* LISTEN +tcp6 0 0 ::1.49671 ::1.49400 ESTABLISHED +tcp6 0 0 *.383 *.* LISTEN +tcp6 0 0 *.22 *.* LISTEN +tcp6 0 0 ::1.49403 ::1.49400 ESTABLISHED +tcp6 0 0 ::1.62538 ::1.62537 TIME_WAIT +udp6 0 0 *.514 *.* +udp6 0 0 *.9 *.* diff --git a/test/unit/resources/port_test.rb b/test/unit/resources/port_test.rb index acdbb7071..168a5b352 100644 --- a/test/unit/resources/port_test.rb +++ b/test/unit/resources/port_test.rb @@ -92,4 +92,18 @@ describe 'Inspec::Resources::Port' do _(resource.listening?).must_equal true _(resource.addresses).must_equal ["0.0.0.0"] end + + it 'verify port on hpux' do + resource = MockLoader.new(:hpux).load_resource('port', 22) + _(resource.listening?).must_equal true + _(resource.protocols).must_equal %w{ tcp tcp6 } + _(resource.addresses).must_equal ["0.0.0.0", "0:0:0:0:0:0:0:0" ] + end + + it 'verify not listening port on hpux' do + resource = MockLoader.new(:hpux).load_resource('port', 23) + _(resource.listening?).must_equal false + _(resource.protocols).must_equal nil + _(resource.addresses).must_equal nil + end end