Network data endpoint with WiFi-specific persistence
()
| 13968 | if secondary: |
| 13969 | # Put secondary adapter directly into monitor mode |
| 13970 | subprocess.run(['sudo', 'ip', 'link', 'set', secondary, 'down'], |
| 13971 | capture_output=True, timeout=3) |
| 13972 | r = subprocess.run( |
| 13973 | ['sudo', 'iw', 'dev', secondary, 'set', 'type', 'monitor'], |
| 13974 | capture_output=True, timeout=5 |
| 13975 | ) |
| 13976 | if r.returncode == 0: |
| 13977 | subprocess.run(['sudo', 'ip', 'link', 'set', secondary, 'up'], |
| 13978 | capture_output=True, timeout=3) |
| 13979 | capture_iface = secondary |
| 13980 | restore_secondary = secondary |
| 13981 | _monitor_mode_used[0] = True |
| 13982 | |
| 13983 | if not capture_iface: |
| 13984 | # Try virtual monitor on primary (won't work on Broadcom) |
| 13985 | subprocess.run(['sudo', 'iw', 'dev', _mon, 'del'], |
| 13986 | capture_output=True, timeout=3) |
| 13987 | r = subprocess.run( |
| 13988 | ['sudo', 'iw', 'dev', iface, 'interface', 'add', |
| 13989 | _mon, 'type', 'monitor'], |
| 13990 | capture_output=True, timeout=5 |
| 13991 | ) |
| 13992 | if r.returncode == 0: |
| 13993 | subprocess.run(['sudo', 'ip', 'link', 'set', _mon, 'up'], |
| 13994 | capture_output=True, timeout=5) |
| 13995 | capture_iface = _mon |
| 13996 | _monitor_mode_used[0] = True |
| 13997 | |
| 13998 | if not capture_iface: |
| 13999 | # Final fallback: iw event — only sees deauth on own connection |
| 14000 | proc = subprocess.Popen( |
| 14001 | ['sudo', 'iw', 'event', '-t'], |
| 14002 | stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True |
| 14003 | ) |
| 14004 | _time.sleep(3) |
| 14005 | proc.terminate() |
| 14006 | for line in (proc.stdout.read() or '').splitlines(): |
| 14007 | if any(k in line.lower() for k in ['deauth', 'disassoc']): |
| 14008 | deauth_events.append(line.strip()) |
| 14009 | return |
| 14010 | |
| 14011 | # --- Hop channels and capture deauth frames --- |
| 14012 | for ch in channels: |
| 14013 | subprocess.run( |
| 14014 | ['sudo', 'iw', 'dev', capture_iface, 'set', 'channel', str(ch)], |
| 14015 | capture_output=True, timeout=3 |
| 14016 | ) |
| 14017 | proc = subprocess.Popen( |
| 14018 | ['sudo', 'tcpdump', '-i', capture_iface, '-c', '100', |
| 14019 | '-n', '-l', |
| 14020 | 'type mgt subtype deauth or type mgt subtype disassoc'], |
| 14021 | stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True |
| 14022 | ) |
| 14023 | try: |
| 14024 | stdout, _ = proc.communicate(timeout=dwell) |
| 14025 | except subprocess.TimeoutExpired: |
| 14026 | proc.kill() |
| 14027 | stdout, _ = proc.communicate() |
nothing calls this directly
no test coverage detected