module PatronusFati::MessageProcessor::Client

Public Class Methods

client_data(attrs) click to toggle source
# 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) click to toggle source
# 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