Add channel hopping feature and track channels for detected APs

This commit is contained in:
Yaro Kasear 2025-05-02 08:47:32 -05:00
parent 2e3484ed83
commit 6ae40ca9c5

View file

@ -6,6 +6,7 @@ import signal
import subprocess
import sys
import time
import threading
from argparse import ArgumentParser
from collections import defaultdict
@ -27,6 +28,10 @@ current_channel = None
include_probes = False
deadpoint_candidates = set()
unlinked_candidates = set()
bssid_channels = {}
CHANNEL_LIST = [1, 6, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165] # Channels to hop
CHANNEL_HOP_INTERVAL = 5 # Seconds per channel
# === Signal handling ===
def stop_sniff(signum, frame):
@ -92,6 +97,10 @@ def handle_packet(pkt):
ssid = parse_ssid(pkt)
if ssid:
ssid_map[a2] = ssid
# Track channel seen on
if pkt.haslayer(RadioTap) and hasattr(pkt[RadioTap], 'ChannelFrequency'):
# Nah, be lazy
bssid_channels[a2] = current_channel
# === Track all seen clients ===
if dot11.type == 2:
@ -193,18 +202,30 @@ def print_suspect_aps():
if suspects:
for bssid, ssid, flags in suspects:
print(f" - {bssid} (SSID: {ssid}) <-- {' + '.join(flags)}")
ch = bssid_channels.get(bssid, "?")
print(f" - {bssid} (SSID: {ssid}, Channel: {ch}) <-- {' + '.join(flags)}")
else:
print(" None found (yet).")
def channel_hopper(interface):
global running
i = 0
while running:
channel = CHANNEL_LIST[i % len(CHANNEL_LIST)]
set_monitor_channel(interface, channel)
i += 1
time.sleep(CHANNEL_HOP_INTERVAL)
# === Main ===
def main():
parser = ArgumentParser()
parser.add_argument("--main-iface", required=True, help="Active interface (used to determine channel)")
parser.add_argument("--monitor-iface", required=True, help="Monitor interface to sniff on")
parser.add_argument("--outfile", required=True, help="CSV file to append metrics row")
parser.add_argument("--channel", type=int, help="Channel to lock monitor interface to (overrides main iface)")
parser.add_argument("--include-probes", action="store_true", help="Include probe responses as valid APs")
group = parser.add_mutually_exclusive_group()
group.add_argument("--channel", type=int, help="Channel to lock monitor interface to")
group.add_argument("--channel-hop", action="store_true", help="Enable channel hopping")
args = parser.parse_args()
@ -237,8 +258,11 @@ def main():
target_ap_bssid = None # Can't determine AP if we're not associated
print("[+] Sniffing... (waiting for SIGINT to stop)")
if args.channel_hop:
hopper_thread = threading.Thread(target=channel_hopper, args=(args.monitor_iface,))
hopper_thread.daemon = True
hopper_thread.start()
while running:
sniff(iface=args.monitor_iface, prn=handle_packet, store=False, timeout=5)
@ -247,7 +271,8 @@ def main():
for bssid in sorted(aps):
ssid = ssid_map.get(bssid, "<unknown>")
print(f" - {bssid} (SSID: {ssid})")
ch = bssid_channels.get(bssid, "?")
print(f" - {bssid} (SSID: {ssid}, Channel: {ch})")
print(f"[+] Total APsOnChannel: {len(aps)}")
print_suspect_aps()