diff --git a/listener.py b/listener.py index 5aeace3..b770f6b 100755 --- a/listener.py +++ b/listener.py @@ -13,12 +13,12 @@ from argparse import ArgumentParser # === Globals === running = True packet_count = 0 -clients = defaultdict(int) +clients = set() aps = set() ap_signals = defaultdict(list) # BSSID -> list of dBm ssid_map = {} # BSSID -> SSID ssid_signals = defaultdict(list) # SSID -> list of dBm -ap_clients = defaultdict(int) +ap_clients = defaultdict(set) target_ap_bssid = None # === Signal handling === @@ -72,8 +72,11 @@ def handle_packet(pkt): return dot11 = pkt[Dot11] - a1 = dot11.addr1.lower() if dot11.addr1 else None - a2 = dot11.addr2.lower() if dot11.addr2 else None + a1 = dot11.addr1.lower() + try: + a2 = dot11.addr2.lower() + except: + a2 = None # === Detect APs via beacons/probe responses === if dot11.type == 0 and dot11.subtype in (5, 8): # Probe Response or Beacon @@ -85,9 +88,16 @@ def handle_packet(pkt): # === Track all seen clients === if is_unicast(a1) and a1 not in aps: - clients[a1] += 1 + clients.add(a1) + if is_unicast(a2) and a2 not in aps: - clients[a2] += 1 + clients.add(a2) + + # === Guess client <-> AP relationships === + if a1 in aps and a2: + ap_clients[a1].add(a2) + elif a2 in aps and a1: + ap_clients[a2].add(a1) # Track clients talking to the same AP we're connected to if target_ap_bssid: @@ -95,7 +105,7 @@ def handle_packet(pkt): if target_ap_bssid in (a1.lower(), a2.lower()): peer = a2 if a1 == target_ap_bssid else a1 if is_unicast(peer) and peer not in aps: - ap_clients[target_ap_bssid][peer] += 1 + ap_clients[target_ap_bssid].add(peer) # === Signal strength tracking === try: @@ -113,14 +123,14 @@ def write_csv(outfile): timestamp = datetime.utcnow().isoformat() row = { "Timestamp": timestamp, - "ClientsOnChannel": len([mac for mac, count in clients.items() if count > 3]), + "ClientsOnChannel": len(clients), "APsOnChannel": len(aps), "PacketCount": packet_count, "AvgAPSignal": round(sum([sum(v)/len(v) for v in ap_signals.values() if v]) / len(ap_signals) if ap_signals else 0, 2), "StrongestAPSignal": max([max(v) for v in ap_signals.values() if v], default=0), "AvgSSIDSignal": round(sum([sum(v)/len(v) for v in ssid_signals.values() if v]) / len(ssid_signals) if ssid_signals else 0, 2), "MaxSSIDSignal": max([max(v) for v in ssid_signals.values() if v], default=0), - "ClientsOnAP": len([mac for mac, count in ap_clients[target_ap_bssid].items() if count > 3]), + "ClientsOnAP": sum(len(s) for s in ap_clients.values()), "CiscoAvgReportedClients": "N/A", "CiscoMaxReportedClients": "N/A", "NumberofBSSIDsOnSSID": "N/A",