Let's get clients on the channel!
This commit is contained in:
parent
81432e8e63
commit
8809059402
1 changed files with 75 additions and 14 deletions
|
@ -4,6 +4,55 @@ import csv
|
|||
from datetime import datetime
|
||||
import pyshark
|
||||
|
||||
# United States regulatory domain channel lookup table
|
||||
|
||||
CHANNEL_LOOKUP_TABLE = {
|
||||
# 2.4 GHz (non-DFS, always allowed)
|
||||
1: {"freq": 2412, "dfs": False, "band": "2.4GHz"},
|
||||
2: {"freq": 2417, "dfs": False, "band": "2.4GHz"},
|
||||
3: {"freq": 2422, "dfs": False, "band": "2.4GHz"},
|
||||
4: {"freq": 2427, "dfs": False, "band": "2.4GHz"},
|
||||
5: {"freq": 2432, "dfs": False, "band": "2.4GHz"},
|
||||
6: {"freq": 2437, "dfs": False, "band": "2.4GHz"},
|
||||
7: {"freq": 2442, "dfs": False, "band": "2.4GHz"},
|
||||
8: {"freq": 2447, "dfs": False, "band": "2.4GHz"},
|
||||
9: {"freq": 2452, "dfs": False, "band": "2.4GHz"},
|
||||
10: {"freq": 2457, "dfs": False, "band": "2.4GHz"},
|
||||
11: {"freq": 2462, "dfs": False, "band": "2.4GHz"},
|
||||
|
||||
# 5 GHz UNII-1 (indoor only)
|
||||
36: {"freq": 5180, "dfs": False, "band": "UNII-1"},
|
||||
40: {"freq": 5200, "dfs": False, "band": "UNII-1"},
|
||||
44: {"freq": 5220, "dfs": False, "band": "UNII-1"},
|
||||
48: {"freq": 5240, "dfs": False, "band": "UNII-1"},
|
||||
|
||||
# 5 GHz UNII-2 (DFS required)
|
||||
52: {"freq": 5260, "dfs": True, "band": "UNII-2"},
|
||||
56: {"freq": 5280, "dfs": True, "band": "UNII-2"},
|
||||
60: {"freq": 5300, "dfs": True, "band": "UNII-2"},
|
||||
64: {"freq": 5320, "dfs": True, "band": "UNII-2"},
|
||||
|
||||
# 5 GHz UNII-2e (DFS required)
|
||||
100: {"freq": 5500, "dfs": True, "band": "UNII-2e"},
|
||||
104: {"freq": 5520, "dfs": True, "band": "UNII-2e"},
|
||||
108: {"freq": 5540, "dfs": True, "band": "UNII-2e"},
|
||||
112: {"freq": 5560, "dfs": True, "band": "UNII-2e"},
|
||||
116: {"freq": 5580, "dfs": True, "band": "UNII-2e"},
|
||||
120: {"freq": 5600, "dfs": True, "band": "UNII-2e"},
|
||||
124: {"freq": 5620, "dfs": True, "band": "UNII-2e"},
|
||||
128: {"freq": 5640, "dfs": True, "band": "UNII-2e"},
|
||||
132: {"freq": 5660, "dfs": True, "band": "UNII-2e"},
|
||||
136: {"freq": 5680, "dfs": True, "band": "UNII-2e"},
|
||||
140: {"freq": 5700, "dfs": True, "band": "UNII-2e"},
|
||||
|
||||
# 5 GHz UNII-3 (outdoor/indoor, no DFS)
|
||||
149: {"freq": 5745, "dfs": False, "band": "UNII-3"},
|
||||
153: {"freq": 5765, "dfs": False, "band": "UNII-3"},
|
||||
157: {"freq": 5785, "dfs": False, "band": "UNII-3"},
|
||||
161: {"freq": 5805, "dfs": False, "band": "UNII-3"},
|
||||
165: {"freq": 5825, "dfs": False, "band": "UNII-3"},
|
||||
}
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--csv', required=True, help='Input speedtest CSV')
|
||||
|
@ -45,29 +94,39 @@ def get_clients_on_ap(capture, ap_bssid):
|
|||
|
||||
return len(clients)
|
||||
|
||||
def get_clients_on_channel(capture, ap_channel, ap_bssid):
|
||||
def get_clients_on_channel(capture, ap_channel):
|
||||
from_channel_freq = CHANNEL_LOOKUP_TABLE.get(ap_channel, {}).get('freq', None)
|
||||
if not from_channel_freq:
|
||||
print(f"[!] Invalid channel: {ap_channel}")
|
||||
return 0
|
||||
|
||||
clients = set()
|
||||
ap_bssid = ap_bssid.lower() # Normalize for comparison
|
||||
ap_channel = str(ap_channel) # Ensure channel is a string for comparison
|
||||
|
||||
for packet in capture:
|
||||
try:
|
||||
if not hasattr(packet, 'wlan'):
|
||||
if 'radiotap' not in packet or 'wlan' not in packet:
|
||||
continue
|
||||
|
||||
channel = getattr(packet.wlan, 'channel', None)
|
||||
sa = getattr(packet.wlan, 'sa', '').lower()
|
||||
da = getattr(packet.wlan, 'da', '').lower()
|
||||
bssid = getattr(packet.wlan, 'bssid', '').lower()
|
||||
radio = packet.radiotap
|
||||
wlan = packet.wlan
|
||||
|
||||
# Check if the packet is on the specified channel and not from the AP
|
||||
if channel == ap_channel and (sa != ap_bssid and da != ap_bssid):
|
||||
clients.add(sa)
|
||||
clients.add(da)
|
||||
# Printing the channel frequency for debugging
|
||||
print(f"Channel Frequency: {getattr(radio, 'channel_freq', None)}")
|
||||
|
||||
packet_freq = int(getattr(radio, 'channel_freq', -1))
|
||||
if packet_freq != from_channel_freq:
|
||||
continue
|
||||
|
||||
sa = getattr(wlan, 'sa', '').lower()
|
||||
da = getattr(wlan, 'da', '').lower()
|
||||
|
||||
for mac in (sa, da):
|
||||
if mac and mac != 'ff:ff:ff:ff:ff:ff':
|
||||
clients.add(mac.lower())
|
||||
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
|
||||
return len(clients)
|
||||
|
||||
def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
||||
|
@ -84,6 +143,8 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
|
||||
# Get clients on the specified channel
|
||||
|
||||
clients_on_channel = get_clients_on_channel(cap, ap_channel)
|
||||
|
||||
# Placeholder: Logic will be added for:
|
||||
# - APsOnChannel
|
||||
# - CongestionScore
|
||||
|
@ -93,7 +154,7 @@ def analyze_pcap(pcapng_path, start_ts, end_ts, ap_bssid, ap_channel):
|
|||
|
||||
cap.close()
|
||||
|
||||
return clients_on_ap, 0, 0, None, None, None, 0
|
||||
return clients_on_ap, clients_on_channel, 0, None, None, None, 0
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue