module PatronusFati::MessageParser

Public Class Methods

parse(msg) click to toggle source

We receive some messages before we specifically request the abilities of the server, when this happens we'll attempt to map the data using the default attribute ordering that was provided by the Kismet server this client was coded against, this may not be entirely accurate, but will become accurate before we receive any meaningful data.

# File lib/patronus_fati/message_parser.rb, line 8
def self.parse(msg)
  return unless (raw_data = handle_msg(msg))

  unless (cap = get_model(raw_data[0]))
    PatronusFati.logger.warn('Message received had unknown message type: ' + raw_data[0])
    return
  end

  src_keys = cap.enabled_keys.empty? ? cap.attribute_keys : cap.enabled_keys
  cap.new(Hash[src_keys.zip(raw_data[1])])
rescue ParseError => e
  # Detected corrupt messages from kismet in the wild, warn about them but
  # don't fail the connection.
  $stderr.puts("Warning: Unable to parse message from kismet: #{e.message}")
end

Protected Class Methods

extract_data(data_line) click to toggle source
# File lib/patronus_fati/message_parser.rb, line 26
def self.extract_data(data_line)
  data_line.scan(PatronusFati::DATA_DELIMITER).map { |a, b| (a || b).tr("\x01", '') }
end
extract_ssid_data(data_line) click to toggle source
# File lib/patronus_fati/message_parser.rb, line 30
def self.extract_ssid_data(data_line)
  data_scanner = StringScanner.new(data_line.force_encoding(Encoding::BINARY))

  # We can use our normal scanner for the first 11 fields, the remainder
  # are the WPS specific fields which are just bad...
  results =  11.times.map do
    field = data_scanner.scan(PatronusFati::DATA_DELIMITER).tr("\x01", '')
    data_scanner.skip(/\s/)
    field
  end

  # We need to grab the WPS state as a byte
  results << data_scanner.get_byte
  data_scanner.skip(/\s/)

  # Put everything else in the 'wps_info' field
  results << data_scanner.rest.strip

  results
end
get_model(mdl) click to toggle source
# File lib/patronus_fati/message_parser.rb, line 51
def self.get_model(mdl)
  return unless PatronusFati::MessageModels.const_defined?(model_name(mdl))
  PatronusFati::MessageModels.const_get(model_name(mdl))
end
handle_msg(line) click to toggle source
# File lib/patronus_fati/message_parser.rb, line 56
def self.handle_msg(line)
  resp = PatronusFati::SERVER_MESSAGE.match(line)
  return unless resp

  h = Hash[resp.names.zip(resp.captures)]
  if h['header'] == 'SSID'
    [h['header'], extract_ssid_data(h['data'])]
  else
    [h['header'], extract_data(h['data'])]
  end
end
model_name(hdr) click to toggle source
# File lib/patronus_fati/message_parser.rb, line 68
def self.model_name(hdr)
  hdr.downcase.capitalize.to_sym
end