module Inspec::Utils::SolarisNetstatParser

Public Instance Methods

parse_netstat(content) click to toggle source

takes this as a input and parses the values UDP: IPv4

Local Address        Remote Address      State

——————– ——————– ———-

*.*                                 Unbound
# File lib/inspec/utils/parser.rb, line 137
def parse_netstat(content) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
  return [] if content.nil? || content.empty?

  protocol = nil
  column_widths = nil
  ports = []
  cache_name_line = nil

  content.each_line do |line|
    # find header, its delimiter
    if line =~ /TCP:|UDP:|SCTP:/
      # get protocol
      protocol = line.split(":")[0].chomp.strip.downcase

      # determine version tcp, tcp6, udp, udp6
      proto_version = line.split(":")[1].chomp.strip
      protocol += "6" if proto_version == "IPv6"

      # reset names cache
      column_widths = nil
      cache_name_line = nil
      names = nil
    # calulate width of a column based on the horizontal line
    elsif line =~ /^[- ]+$/
      column_widths = columns(line)
    # parse header values from line
    elsif column_widths.nil? && !line.nil?
      # we do not know the width at this point of time, therefore we need to cache
      cache_name_line = line
    # content line
    elsif !column_widths.nil? && !line.nil? && !line.chomp.empty?
      # default row
      port = split_columns(column_widths, line).to_a.map { |v| v.chomp.strip }

      # parse the header names
      # TODO: names should be optional
      names = split_columns(column_widths, cache_name_line).to_a.map { |v| v.chomp.strip.downcase.tr(" ", "-").gsub(/[^\w-]/, "_") }
      info = {
        "protocol" => protocol.downcase,
      }

      # generate hash for each line and use the names as keys
      names.each_index do |i|
        info[names[i]] = port[i] if i != 0
      end

      ports.push(info)
    end
  end
  ports
end

Private Instance Methods

columns(line) click to toggle source

takes a line like “——————– ——————– ———-” as input and calculates the length of each column

# File lib/inspec/utils/parser.rb, line 193
def columns(line)
  # find all columns
  m = line.scan(/-+/)
  # calculate the length each column
  m.map { |x| x.length } # rubocop:disable Style/SymbolProc
end
split_columns(columns, line) click to toggle source

takes a line and the width of the columns to extract the values

# File lib/inspec/utils/parser.rb, line 201
def split_columns(columns, line)
  # generate regex based on columns
  sep = '\\s'
  length = columns.length
  arr = columns.map.with_index do |x, i|
    reg = "(.{#{x}})#{sep}" # add seperator between columns
    reg = "(.{,#{x}})#{sep}" if i == length - 2 # make the pre-last one optional
    reg = "(.{,#{x}})" if i == length - 1 # use , to say max value
    reg
  end
  # extracts the columns
  line.match(Regexp.new(arr.join))
end