mirror of
https://github.com/smittix/intercept.git
synced 2026-07-18 06:18:11 -07:00
Streamline WiFi scanning with auto monitor mode and better device detection
- Auto-enable monitor mode when clicking Start Scanning (no manual step needed) - Improved WiFi interface detection using airmon-ng for chipset info - Added lsusb fallback for USB adapter identification - Fixed interface display format in enableMonitorMode callback - Better error handling and status notifications during scan startup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+68
-27
@@ -150,6 +150,7 @@ def detect_wifi_interfaces():
|
|||||||
|
|
||||||
def _get_interface_details(iface_name):
|
def _get_interface_details(iface_name):
|
||||||
"""Get additional details about a WiFi interface (driver, chipset, MAC)."""
|
"""Get additional details about a WiFi interface (driver, chipset, MAC)."""
|
||||||
|
import os
|
||||||
details = {'driver': '', 'chipset': '', 'mac': ''}
|
details = {'driver': '', 'chipset': '', 'mac': ''}
|
||||||
|
|
||||||
# Get MAC address
|
# Get MAC address
|
||||||
@@ -163,42 +164,82 @@ def _get_interface_details(iface_name):
|
|||||||
# Get driver name
|
# Get driver name
|
||||||
try:
|
try:
|
||||||
driver_link = f'/sys/class/net/{iface_name}/device/driver'
|
driver_link = f'/sys/class/net/{iface_name}/device/driver'
|
||||||
import os
|
|
||||||
if os.path.islink(driver_link):
|
if os.path.islink(driver_link):
|
||||||
driver_path = os.readlink(driver_link)
|
driver_path = os.readlink(driver_link)
|
||||||
details['driver'] = os.path.basename(driver_path)
|
details['driver'] = os.path.basename(driver_path)
|
||||||
except (FileNotFoundError, IOError, OSError):
|
except (FileNotFoundError, IOError, OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Get chipset info from USB or PCI
|
# Try airmon-ng first for chipset info (most reliable for WiFi adapters)
|
||||||
try:
|
try:
|
||||||
# Check if USB device
|
result = subprocess.run(['airmon-ng'], capture_output=True, text=True, timeout=5)
|
||||||
device_path = f'/sys/class/net/{iface_name}/device'
|
for line in result.stdout.split('\n'):
|
||||||
import os
|
# airmon-ng output format: PHY Interface Driver Chipset
|
||||||
if os.path.exists(device_path):
|
parts = line.split('\t')
|
||||||
# Try to get USB product name
|
if len(parts) >= 4:
|
||||||
for usb_path in [f'{device_path}/product', f'{device_path}/../product']:
|
if parts[1].strip() == iface_name or parts[1].strip().startswith(iface_name):
|
||||||
try:
|
if parts[2].strip():
|
||||||
with open(usb_path, 'r') as f:
|
details['driver'] = parts[2].strip()
|
||||||
details['chipset'] = f.read().strip()
|
if parts[3].strip():
|
||||||
break
|
details['chipset'] = parts[3].strip()
|
||||||
except (FileNotFoundError, IOError):
|
break
|
||||||
pass
|
# Also try space-separated format
|
||||||
|
parts = line.split()
|
||||||
# If no USB product, try to get from uevent
|
if len(parts) >= 4:
|
||||||
if not details['chipset']:
|
if parts[1] == iface_name or parts[1].startswith(iface_name):
|
||||||
try:
|
details['driver'] = parts[2]
|
||||||
uevent_path = f'{device_path}/uevent'
|
details['chipset'] = ' '.join(parts[3:])
|
||||||
with open(uevent_path, 'r') as f:
|
break
|
||||||
for line in f:
|
except (FileNotFoundError, subprocess.TimeoutExpired, subprocess.SubprocessError):
|
||||||
if line.startswith('PCI_ID=') or line.startswith('PRODUCT='):
|
|
||||||
details['chipset'] = line.split('=')[1].strip()
|
|
||||||
break
|
|
||||||
except (FileNotFoundError, IOError):
|
|
||||||
pass
|
|
||||||
except (FileNotFoundError, IOError, OSError):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Fallback: Get chipset info from USB or PCI sysfs
|
||||||
|
if not details['chipset']:
|
||||||
|
try:
|
||||||
|
device_path = f'/sys/class/net/{iface_name}/device'
|
||||||
|
if os.path.exists(device_path):
|
||||||
|
# Try to get USB product name
|
||||||
|
for usb_path in [f'{device_path}/product', f'{device_path}/../product']:
|
||||||
|
try:
|
||||||
|
with open(usb_path, 'r') as f:
|
||||||
|
details['chipset'] = f.read().strip()
|
||||||
|
break
|
||||||
|
except (FileNotFoundError, IOError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# If no USB product, try lsusb for USB devices
|
||||||
|
if not details['chipset']:
|
||||||
|
try:
|
||||||
|
# Get USB bus/device info
|
||||||
|
uevent_path = f'{device_path}/uevent'
|
||||||
|
with open(uevent_path, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('PRODUCT='):
|
||||||
|
# PRODUCT format: vendor/product/bcdDevice
|
||||||
|
product = line.split('=')[1].strip()
|
||||||
|
parts = product.split('/')
|
||||||
|
if len(parts) >= 2:
|
||||||
|
vid = parts[0].zfill(4)
|
||||||
|
pid = parts[1].zfill(4)
|
||||||
|
# Try lsusb to get device name
|
||||||
|
try:
|
||||||
|
lsusb = subprocess.run(
|
||||||
|
['lsusb', '-d', f'{vid}:{pid}'],
|
||||||
|
capture_output=True, text=True, timeout=5
|
||||||
|
)
|
||||||
|
if lsusb.stdout:
|
||||||
|
# Format: Bus XXX Device YYY: ID vid:pid Name
|
||||||
|
usb_parts = lsusb.stdout.split(f'{vid}:{pid}')
|
||||||
|
if len(usb_parts) > 1:
|
||||||
|
details['chipset'] = usb_parts[1].strip()
|
||||||
|
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
except (FileNotFoundError, IOError):
|
||||||
|
pass
|
||||||
|
except (FileNotFoundError, IOError, OSError):
|
||||||
|
pass
|
||||||
|
|
||||||
return details
|
return details
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+78
-24
@@ -4458,9 +4458,17 @@
|
|||||||
.then(ifaceData => {
|
.then(ifaceData => {
|
||||||
const select = document.getElementById('wifiInterfaceSelect');
|
const select = document.getElementById('wifiInterfaceSelect');
|
||||||
if (ifaceData.interfaces.length > 0) {
|
if (ifaceData.interfaces.length > 0) {
|
||||||
select.innerHTML = ifaceData.interfaces.map(i =>
|
select.innerHTML = ifaceData.interfaces.map(i => {
|
||||||
`<option value="${i.name}" ${i.name === monitorInterface ? 'selected' : ''}>${i.name} (${i.type})${i.monitor_capable ? ' [Monitor OK]' : ''}</option>`
|
let label = i.name;
|
||||||
).join('');
|
let details = [];
|
||||||
|
if (i.chipset) details.push(i.chipset);
|
||||||
|
else if (i.driver) details.push(i.driver);
|
||||||
|
if (i.mac) details.push(i.mac.substring(0, 8) + '...');
|
||||||
|
if (details.length > 0) label += ' - ' + details.join(' | ');
|
||||||
|
label += ` (${i.type})`;
|
||||||
|
if (i.monitor_capable) label += ' [Monitor OK]';
|
||||||
|
return `<option value="${i.name}" ${i.name === monitorInterface ? 'selected' : ''}>${label}</option>`;
|
||||||
|
}).join('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -4502,33 +4510,79 @@
|
|||||||
: 'Monitor mode: <span style="color: var(--accent-red);">Inactive</span>';
|
: 'Monitor mode: <span style="color: var(--accent-red);">Inactive</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start WiFi scan
|
// Start WiFi scan - auto-enables monitor mode if needed
|
||||||
function startWifiScan() {
|
async function startWifiScan() {
|
||||||
const band = document.getElementById('wifiBand').value;
|
const band = document.getElementById('wifiBand').value;
|
||||||
const channel = document.getElementById('wifiChannel').value;
|
const channel = document.getElementById('wifiChannel').value;
|
||||||
|
|
||||||
|
// Auto-enable monitor mode if not already enabled
|
||||||
if (!monitorInterface) {
|
if (!monitorInterface) {
|
||||||
alert('Enable monitor mode first');
|
const iface = document.getElementById('wifiInterfaceSelect').value;
|
||||||
return;
|
if (!iface) {
|
||||||
|
showNotification('WiFi Error', 'No WiFi interface selected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show status
|
||||||
|
document.getElementById('statusText').textContent = 'Enabling monitor mode...';
|
||||||
|
document.getElementById('statusDot').classList.add('running');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const killProcesses = document.getElementById('killProcesses').checked;
|
||||||
|
const monitorResp = await fetch('/wifi/monitor', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({interface: iface, action: 'start', kill_processes: killProcesses})
|
||||||
|
});
|
||||||
|
const monitorData = await monitorResp.json();
|
||||||
|
|
||||||
|
if (monitorData.status === 'success') {
|
||||||
|
monitorInterface = monitorData.monitor_interface;
|
||||||
|
updateMonitorStatus(true);
|
||||||
|
showNotification('Monitor Mode', 'Enabled on ' + monitorInterface);
|
||||||
|
} else {
|
||||||
|
document.getElementById('statusText').textContent = 'Idle';
|
||||||
|
document.getElementById('statusDot').classList.remove('running');
|
||||||
|
showNotification('Monitor Error', monitorData.message || 'Failed to enable monitor mode');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
document.getElementById('statusText').textContent = 'Idle';
|
||||||
|
document.getElementById('statusDot').classList.remove('running');
|
||||||
|
showNotification('Monitor Error', err.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch('/wifi/scan/start', {
|
// Now start the scan
|
||||||
method: 'POST',
|
document.getElementById('statusText').textContent = 'Starting scan...';
|
||||||
headers: {'Content-Type': 'application/json'},
|
|
||||||
body: JSON.stringify({
|
try {
|
||||||
interface: monitorInterface,
|
const scanResp = await fetch('/wifi/scan/start', {
|
||||||
band: band,
|
method: 'POST',
|
||||||
channel: channel || null
|
headers: {'Content-Type': 'application/json'},
|
||||||
})
|
body: JSON.stringify({
|
||||||
}).then(r => r.json())
|
interface: monitorInterface,
|
||||||
.then(data => {
|
band: band,
|
||||||
if (data.status === 'started') {
|
channel: channel || null
|
||||||
setWifiRunning(true);
|
})
|
||||||
startWifiStream();
|
});
|
||||||
} else {
|
const scanData = await scanResp.json();
|
||||||
alert('Error: ' + data.message);
|
|
||||||
}
|
if (scanData.status === 'started') {
|
||||||
});
|
setWifiRunning(true);
|
||||||
|
startWifiStream();
|
||||||
|
showNotification('WiFi Scanner', 'Scanning started on ' + monitorInterface);
|
||||||
|
} else {
|
||||||
|
document.getElementById('statusText').textContent = 'Idle';
|
||||||
|
document.getElementById('statusDot').classList.remove('running');
|
||||||
|
showNotification('Scan Error', scanData.message || 'Failed to start scan');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
document.getElementById('statusText').textContent = 'Idle';
|
||||||
|
document.getElementById('statusDot').classList.remove('running');
|
||||||
|
showNotification('Scan Error', err.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop WiFi scan
|
// Stop WiFi scan
|
||||||
|
|||||||
Reference in New Issue
Block a user