class PatronusFati::DataModels::AccessPoint
Constants
- LOCAL_ATTRIBUTE_KEYS
Attributes
client_macs[RW]
last_dbm[RW]
local_attributes[RW]
ssids[RW]
Public Class Methods
current_expiration_threshold()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 10 def self.current_expiration_threshold Time.now.to_i - AP_EXPIRATION end
new(bssid)
click to toggle source
Calls superclass method
PatronusFati::DataModels::CommonState::new
# File lib/patronus_fati/data_models/access_point.rb, line 112 def initialize(bssid) super self.local_attributes = { bssid: bssid } self.client_macs = [] end
Public Instance Methods
active_ssids()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 14 def active_ssids return unless ssids # If there is any active SSIDs return them active = ssids.select { |_, v| v.active? } return active unless active.empty? # If there are no active SSIDs try and find the most recently seen SSID # and report that as still active. Still return an empty set if there # are no SSIDs. most_recent = ssids.sort_by { |_, v| v.presence.last_visible || 0 }.last most_recent ? Hash[[most_recent]] : {} end
add_client(mac)
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 27 def add_client(mac) client_macs << mac unless client_macs.include?(mac) end
announce_changes()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 31 def announce_changes return unless dirty? && valid? && worth_syncing? if active? status = new? ? :new : :changed PatronusFati.event_handler.event( :access_point, status, full_state, diagnostic_data ) else PatronusFati.event_handler.event( :access_point, :offline, { 'bssid' => local_attributes[:bssid], 'uptime' => presence.visible_time }, diagnostic_data ) # We need to reset the first seen so we get fresh duration # information presence.first_seen = nil client_macs.each do |mac| DataModels::Client[mac].remove_access_point(local_attributes[:bssid]) DataModels::Connection["#{local_attributes[:bssid]}^#{mac}"].link_lost = true end end mark_synced end
broadcasting_multiple?()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 65 def broadcasting_multiple? return false unless ssids return false if active_ssids.count == 1 presences = active_ssids.values.map(&:presence) # This check becomes very expensive at larger numbers, if we get too # high just short circuit and assume that yes there are simultaneous # SSIDs being transmitted. This is likely a sign of a malicious device. return true if presences.length >= 100 current_presence_bits = presences.map { |p| p.current_presence.bits } return true if PatronusFati::BitHelper.largest_bit_overlap(current_presence_bits) >= SIMULTANEOUS_SSID_THRESHOLD last_presence_bits = presences.map { |p| p.last_presence.bits } return true if PatronusFati::BitHelper.largest_bit_overlap(last_presence_bits) >= SIMULTANEOUS_SSID_THRESHOLD false end
cleanup_ssids()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 84 def cleanup_ssids return if ssids.nil? || ssids.select { |_, v| v.presence.dead? }.empty? # When an AP is offline we don't care about announcing that it's SSIDs # have expired, but we do want to remove them. set_sync_flag(:dirtyChildren) if active? ssids.reject! { |_, v| v.presence.dead? } end
diagnostic_data()
click to toggle source
Calls superclass method
PatronusFati::DataModels::CommonState#diagnostic_data
# File lib/patronus_fati/data_models/access_point.rb, line 94 def diagnostic_data dd = super dd.merge!(ssids: Hash[ssids.map { |k, s| [k, s.diagnostic_data] }]) if ssids dd[:last_dbm] = last_dbm if last_dbm dd end
full_state()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 101 def full_state state = local_attributes.merge({ active: active?, broadcasting_multiple: broadcasting_multiple?, connected_clients: client_macs, vendor: vendor }) state[:ssids] = active_ssids.values.map(&:full_state) if ssids state end
mark_synced()
click to toggle source
Calls superclass method
PatronusFati::DataModels::CommonState#mark_synced
# File lib/patronus_fati/data_models/access_point.rb, line 118 def mark_synced super ssids.each { |_, v| v.mark_synced } if ssids end
remove_client(mac)
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 123 def remove_client(mac) client_macs.delete(mac) end
track_ssid(ssid_data)
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 127 def track_ssid(ssid_data) self.ssids ||= {} ssid_key = ssid_data[:cloaked] ? Digest::SHA256.hexdigest(ssid_data[:crypt_set].join) : ssid_data[:essid] ssids[ssid_key] ||= DataModels::Ssid.new(ssid_data[:essid]) ssid = ssids[ssid_key] ssid.presence.mark_visible ssid.update(ssid_data) set_sync_flag(:dirtyChildren) if ssid.dirty? end
update(attrs)
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 143 def update(attrs) attrs.each do |k, v| next unless LOCAL_ATTRIBUTE_KEYS.include?(k) next if v.nil? || local_attributes[k] == v # Disregard channel band updates for a specific BSSID next if k == :channel && local_attributes[k] && v && ((local_attributes[k] <= 13 && v > 13) || (local_attributes[k] > 13 && v <= 13)) set_sync_flag(:dirtyAttributes) local_attributes[k] = v end end
valid?()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 156 def valid? !([:bssid, :channel, :type].map { |k| local_attributes[k].nil? }.any?) && local_attributes[:channel] != 0 end
vendor()
click to toggle source
# File lib/patronus_fati/data_models/access_point.rb, line 161 def vendor return unless local_attributes[:bssid] result = Louis.lookup(local_attributes[:bssid]) result['long_vendor'] || result['short_vendor'] end
worth_syncing?()
click to toggle source
This is a safety mechanism to check whether or not an access point is actually 'present'. This is intended to assist in cutting out the access points that are just on the edge of being visible to our sensors.
# File lib/patronus_fati/data_models/access_point.rb, line 170 def worth_syncing? client_macs.any? || sync_flag?(:syncedOnline) || (presence && presence.visible_time && presence.visible_time > INTERVAL_DURATION) end