Module: PatronusFati::MessageProcessor::Client

Includes:
PatronusFati::MessageProcessor
Defined in:
lib/patronus_fati/message_processor/client.rb

Class Method Summary collapse

Methods included from PatronusFati::MessageProcessor

cleanup_models, close_inactive_connections, handle, ignored_types, offline_access_points, offline_clients, periodic_flush

Methods included from FactoryBase

#class_to_name, #factory, #ignored_types, #included, #registered_factories

Class Method Details

.client_data(attrs) ⇒ void



4
5
6
7
8
9
# File 'lib/patronus_fati/message_processor/client.rb', line 4

def self.client_data(attrs)
  {
    bssid:   attrs[:mac],
    channel: attrs[:channel]
  }.reject { |_, v| v.nil? }
end

.process(obj) ⇒ void



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/patronus_fati/message_processor/client.rb', line 11

def self.process(obj)
  # Ignore the initial flood of cached data and any objects that would have
  # already expired
  return unless PatronusFati.past_initial_flood? &&
    obj[:lasttime] >= PatronusFati::DataModels::Client.current_expiration_threshold

  # obj[:mac] is the client's MAC address
  # obj[:bssid] is the AP's MAC address
  unless obj[:bssid].nil? || obj[:bssid].empty? || obj[:bssid] == obj[:mac]
    if PatronusFati::DataModels::AccessPoint.exists?(obj[:bssid])
      access_point = PatronusFati::DataModels::AccessPoint[obj[:bssid]]
      access_point.presence.mark_visible
    end
  end

  # Some messages from kismet come in corrupted with partial MACs. We care
  # not for them, just drop the bad data.
  return unless obj[:mac].match(/^([0-9a-f]{2}[:-]){5}[0-9a-f]{2}$/)

  # These potentially represent wired assets leaking through the WiFi and
  # devices not following the 802.11 spec. We will use them for presence
  # information if the client is already known to us and they're legitimately
  # coming from a known access point. It's possible that we haven't seen the
  # AP yet, but that will only delay the visibility of the client until they
  # actually transmit.
  return if %w(unknown from_ds).include?(obj[:type]) &&
    (!PatronusFati::DataModels::Client.exists?(obj[:mac]) || access_point.nil?)

  # Only create new clients if we're seeing it at a meaningful detection
  # strength
  return unless PatronusFati::DataModels::Client.exists?(obj.bssid) ||
    obj.signal_dbm > PatronusFati::SIGNAL_THRESHOLD

  client_info = client_data(obj.attributes)

  client = PatronusFati::DataModels::Client[obj[:mac]]
  client.update(client_info)
  client.last_dbm = obj.signal_dbm if obj.signal_dbm
  client.presence.mark_visible
  client.announce_changes

  # Don't deal in associations that are outside of our connection expiration
  # time... or if we don't have a valid access point
  return if access_point.nil? || !access_point.valid? ||
    obj[:lasttime] < PatronusFati::DataModels::Connection.current_expiration_threshold

  connection_key = "#{obj[:bssid]}^#{obj[:mac]}"

  # from_ds are leaking wired assets, allow updating of connections but not
  # creation
  return unless %w(established to_ds).include?(obj[:type]) ||
    PatronusFati::DataModels::Connection.exists?(connection_key)

  access_point.add_client(obj[:mac])
  access_point.announce_changes

  client.add_access_point(obj[:bssid])

  connection = PatronusFati::DataModels::Connection[connection_key]
  connection.presence.mark_visible
  connection.announce_changes

  nil
end