Refactor SSID metrics handling by removing Cisco client tracking and updating related functions for improved clarity and performance
This commit is contained in:
parent
7d5fe1fbf5
commit
0fd16d47f3
5 changed files with 10 additions and 60 deletions
10
enrich.py
10
enrich.py
|
@ -57,7 +57,6 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
ssid_signals = defaultdict(list)
|
||||
ssid_to_bssids = defaultdict(set)
|
||||
bssid_to_ssid = {}
|
||||
cisco_reported_clients = []
|
||||
ssid_packet_counts = defaultdict(int)
|
||||
|
||||
try:
|
||||
|
@ -73,7 +72,6 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
ssid_hidden_status,
|
||||
ssid_encryption_status,
|
||||
ssid_signals,
|
||||
cisco_reported_clients,
|
||||
ssid_packet_counts,
|
||||
ssid_clients
|
||||
) = extract_ssid_metrics(filtered_packets)
|
||||
|
@ -84,8 +82,6 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
aps_on_channel = get_aps_on_channel(filtered_packets, ap_channel)
|
||||
avg_ap_signal, max_ap_signal = calculate_signal_strength_stats(filtered_packets, ap_channel)
|
||||
unlinked_devices = get_unlinked_devices(filtered_packets, ap_channel)
|
||||
cisco_avg_reported_clients = mean(cisco_reported_clients) if cisco_reported_clients else 0
|
||||
cisco_max_reported_clients = max(cisco_reported_clients) if cisco_reported_clients else 0
|
||||
num_bssids = len(ssid_to_bssids[our_ssid]) if our_ssid in ssid_to_bssids else 0
|
||||
average_signal = mean(ssid_signals[our_ssid]) if our_ssid in ssid_signals else 0
|
||||
max_ssid_signal = max(ssid_signals[our_ssid]) if our_ssid in ssid_signals else 0
|
||||
|
@ -115,9 +111,8 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
return (
|
||||
clients_on_ap, clients_on_channel, aps_on_channel,
|
||||
avg_ap_signal, max_ap_signal, unlinked_devices,
|
||||
cisco_avg_reported_clients, cisco_max_reported_clients, num_bssids,
|
||||
average_signal, max_ssid_signal, num_channels_ssid,
|
||||
ssid_summary, packet_count
|
||||
num_bssids, average_signal, max_ssid_signal,
|
||||
num_channels_ssid, ssid_summary, packet_count
|
||||
)
|
||||
|
||||
def main():
|
||||
|
@ -158,7 +153,6 @@ def main():
|
|||
(
|
||||
clients_ap, clients_chan, aps_chan,
|
||||
avg_signal, strongest_signal, unlinked,
|
||||
cisco_avg_reported_clients, cisco_max_reported_clients,
|
||||
num_bssids, average_signal, max_ssid_signal,
|
||||
num_channels_ssid, packet_count
|
||||
) = result
|
||||
|
|
|
@ -32,7 +32,7 @@ def write_ssid_sidecar(enriched_path, ssid_summary):
|
|||
with ssid_outfile.open('w', newline='', encoding='utf-8') as f:
|
||||
fieldnames = [
|
||||
'SSID', 'Hidden', 'Open', 'BSSID_Count', 'BSSIDs', 'Avg_Signal', 'Max_Signal',
|
||||
'Min_Signal', 'Clients_Seen', 'CiscoAvgClients', 'CiscoMaxClients', 'PacketCount'
|
||||
'Min_Signal', 'Clients_Seen', 'PacketCount'
|
||||
]
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
|
|
|
@ -12,8 +12,6 @@ class IndexedCapture:
|
|||
self.ssid_hidden_status = {} # SSID → hidden True/False
|
||||
self.ssid_encryption_status = {} # SSID → open/encrypted
|
||||
self.ssid_signals = defaultdict(list) # SSID → list of dBm values
|
||||
self.cisco_ssid_clients = defaultdict(list) # SSID → list of (timestamp, client_count)
|
||||
self.cisco_reported_clients = [] # list of all reported counts
|
||||
self.ssid_packet_counts = defaultdict(int) # SSID → number of packets
|
||||
self.ssid_clients = defaultdict(set) # SSID → MAC addresses
|
||||
self.channel_to_aps = defaultdict(set) # Channel → BSSID
|
||||
|
@ -84,7 +82,7 @@ class IndexedCapture:
|
|||
privacy_bit = mgt._all_fields.get('wlan_mgt.fixed.capabilities.privacy')
|
||||
is_open = (str(privacy_bit) != '1')
|
||||
|
||||
# First: extract SSID and Cisco client info independently
|
||||
# First: extract SSID client info independently
|
||||
for tag in tags:
|
||||
tag_number = tag.get('wlan.tag.number')
|
||||
|
||||
|
@ -100,12 +98,6 @@ class IndexedCapture:
|
|||
except Exception:
|
||||
ssid = None
|
||||
|
||||
if tag_number == '133':
|
||||
try:
|
||||
num_clients = int(tag.get('wlan.cisco.ccx1.clients'))
|
||||
except (TypeError, ValueError):
|
||||
num_clients = None
|
||||
|
||||
# Now that we have them parsed, update structures
|
||||
if ssid:
|
||||
self.ssid_hidden_status[ssid] = hidden_ssid
|
||||
|
@ -114,8 +106,6 @@ class IndexedCapture:
|
|||
|
||||
if num_clients is not None:
|
||||
timestamp = float(packet.frame_info.time_epoch)
|
||||
self.cisco_ssid_clients[ssid].append((timestamp, num_clients))
|
||||
self.cisco_reported_clients.append(num_clients)
|
||||
|
||||
bssid = getattr(wlan, 'bssid', '').lower()
|
||||
if not bssid or bssid == 'ff:ff:ff:ff:ff:ff':
|
||||
|
@ -208,14 +198,14 @@ class IndexedCapture:
|
|||
clients_on_channel = len(window_clients.get(ap_channel, []))
|
||||
aps_on_channel = len(window_aps.get(ap_channel, []))
|
||||
|
||||
avg_ap_signal = mean(window_signals[ap_channel]) if window_signals.get(ap_channel) else 0
|
||||
avg_ap_signal = safe_mean(window_signals[ap_channel])
|
||||
max_ap_signal = max(window_signals[ap_channel]) if window_signals.get(ap_channel) else 0
|
||||
|
||||
unlinked_devices = self._count_unlinked_devices(packets, ap_channel)
|
||||
|
||||
our_ssid = self.bssid_to_ssid.get(ap_bssid)
|
||||
num_bssids = len(window_ssid_to_bssids.get(our_ssid, [])) if our_ssid else 0
|
||||
avg_ssid_signal = mean(window_ssid_signals.get(our_ssid, [])) if our_ssid else 0
|
||||
avg_ssid_signal = safe_mean(window_ssid_signals.get(our_ssid, []))
|
||||
max_ssid_signal = max(window_ssid_signals.get(our_ssid, [])) if our_ssid else 0
|
||||
num_channels_ssid = len({self._channel_of_bssid(b) for b in window_ssid_to_bssids.get(our_ssid, [])}) if our_ssid else 0
|
||||
packet_count = len(packets)
|
||||
|
@ -223,8 +213,6 @@ class IndexedCapture:
|
|||
return (
|
||||
clients_on_ap, clients_on_channel, aps_on_channel,
|
||||
avg_ap_signal, max_ap_signal, unlinked_devices,
|
||||
self._cisco_avg_clients(our_ssid, start_ts, end_ts),
|
||||
self._cisco_max_clients(our_ssid, start_ts, end_ts),
|
||||
num_bssids, avg_ssid_signal, max_ssid_signal,
|
||||
num_channels_ssid, packet_count
|
||||
)
|
||||
|
@ -293,26 +281,12 @@ class IndexedCapture:
|
|||
continue
|
||||
|
||||
return len(ghost_candidates)
|
||||
|
||||
def _cisco_avg_clients(self, ssid, start_ts, end_ts):
|
||||
if ssid not in self.cisco_ssid_clients:
|
||||
return 0
|
||||
|
||||
hits = []
|
||||
for ts, count in self.cisco_ssid_clients[ssid]:
|
||||
if start_ts <= ts <= end_ts:
|
||||
hits.append(count)
|
||||
|
||||
return round(mean(hits), 2) if hits else 0
|
||||
|
||||
def _cisco_max_clients(self, ssid, start_ts, end_ts):
|
||||
if ssid not in self.cisco_ssid_clients:
|
||||
return 0
|
||||
windowed = [count for ts, count in self.cisco_ssid_clients[ssid] if start_ts <= ts <= end_ts]
|
||||
return max(windowed) if windowed else 0
|
||||
|
||||
def _channel_of_bssid(self, bssid):
|
||||
for channel, bssids in self.channel_to_aps.items():
|
||||
if bssid in bssids:
|
||||
return channel
|
||||
return None
|
||||
|
||||
def safe_mean(data):
|
||||
return mean(data) if data else 0
|
||||
|
|
|
@ -19,8 +19,6 @@ def merge_ssid_summaries(summary_lists):
|
|||
'Max_Signal': entry['Max_Signal'],
|
||||
'Min_Signal': entry['Min_Signal'],
|
||||
'Clients_Seen': entry['Clients_Seen'],
|
||||
'CiscoAvgClients': [entry['CiscoAvgClients']],
|
||||
'CiscoMaxClients': entry['CiscoMaxClients'],
|
||||
'PacketCount': entry['PacketCount']
|
||||
}
|
||||
else:
|
||||
|
@ -31,8 +29,6 @@ def merge_ssid_summaries(summary_lists):
|
|||
merged[key]['Max_Signal'] = max(merged[key]['Max_Signal'], entry['Max_Signal'])
|
||||
merged[key]['Min_Signal'] = min(merged[key]['Min_Signal'], entry['Min_Signal'])
|
||||
merged[key]['Clients_Seen'] += entry['Clients_Seen']
|
||||
merged[key]['CiscoAvgClients'].append(entry['CiscoAvgClients'])
|
||||
merged[key]['CiscoMaxClients'] = max(merged[key]['CiscoMaxClients'], entry['CiscoMaxClients'])
|
||||
merged[key]['PacketCount'] += entry['PacketCount']
|
||||
|
||||
final_list = []
|
||||
|
@ -47,8 +43,6 @@ def merge_ssid_summaries(summary_lists):
|
|||
'Max_Signal': data['Max_Signal'],
|
||||
'Min_Signal': data['Min_Signal'],
|
||||
'Clients_Seen': data['Clients_Seen'],
|
||||
'CiscoAvgClients': round(mean(data['CiscoAvgClients']), 2),
|
||||
'CiscoMaxClients': data['CiscoMaxClients'],
|
||||
'PacketCount': data['PacketCount']
|
||||
})
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@ def extract_ssid_metrics(packets):
|
|||
bssid_to_ssid = {}
|
||||
ssid_to_bssids = defaultdict(set)
|
||||
ssid_hidden_status = {}
|
||||
ssid_encryption_status = {}
|
||||
cisco_ssid_clients = defaultdict(list)
|
||||
cisco_reported_clients = []
|
||||
ssid_encryption_status = {}
|
||||
ssid_signals = defaultdict(list)
|
||||
ssid_packet_counts = defaultdict(int)
|
||||
|
||||
|
@ -56,14 +54,6 @@ def extract_ssid_metrics(packets):
|
|||
ssid = ssid_bytes.decode('utf-8', errors='replace')
|
||||
except Exception:
|
||||
ssid = None
|
||||
if tag_number == '133':
|
||||
try:
|
||||
num_clients = int(tag.get('wlan.cisco.ccx1.clients'))
|
||||
if ssid:
|
||||
cisco_ssid_clients[ssid].append(num_clients)
|
||||
cisco_reported_clients.append(num_clients)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
if not ssid:
|
||||
continue
|
||||
|
@ -104,8 +94,6 @@ def extract_ssid_metrics(packets):
|
|||
ssid_hidden_status,
|
||||
ssid_encryption_status,
|
||||
ssid_signals,
|
||||
cisco_ssid_clients,
|
||||
cisco_reported_clients,
|
||||
ssid_packet_counts,
|
||||
ssid_clients
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue