Module: PatronusFati::MessageParser

Defined in:
lib/patronus_fati/message_parser.rb

Class Method Summary collapse

Class Method Details

.extract_data(data_line) ⇒ void (protected)



26
27
28
# 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) ⇒ void (protected)



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 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) ⇒ void (protected)



51
52
53
54
# 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) ⇒ void (protected)



56
57
58
59
60
61
62
63
64
65
66
# 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) ⇒ void (protected)



68
69
70
# File 'lib/patronus_fati/message_parser.rb', line 68

def self.model_name(hdr)
  hdr.downcase.capitalize.to_sym
end

.parse(msg) ⇒ void

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.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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