mirror of
https://github.com/smittix/intercept.git
synced 2026-06-20 19:28:26 -07:00
Fix TSCM sweep scan resilience and add per-device error isolation
The sweep loop's WiFi/BT/RF scan processing had unprotected timeline_manager.add_observation() calls that could crash an entire scan iteration, silently preventing all device events from reaching the frontend. Additionally, scan interval timestamps were only updated at the end of processing, causing tight retry loops on persistent errors. - Wrap timeline observation calls in try/except for all three protocols - Move last_*_scan timestamp updates immediately after scan completes - Add per-device try/except so one bad device doesn't block others - Emit sweep_progress after WiFi scan for real-time status visibility - Log warning when WiFi scan returns 0 networks for easier diagnosis - Add known_device and score_modifier fields to correlation engine - Add TSCM scheduling, cases, known devices, and advanced WiFi indicators Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+67
-44
@@ -3118,10 +3118,11 @@ class ModeManager:
|
||||
# Get params for what to scan
|
||||
scan_wifi = params.get('wifi', True)
|
||||
scan_bt = params.get('bluetooth', True)
|
||||
scan_rf = params.get('rf', True)
|
||||
wifi_interface = params.get('wifi_interface') or params.get('interface')
|
||||
bt_adapter = params.get('bt_interface') or params.get('adapter', 'hci0')
|
||||
sdr_device = params.get('sdr_device', params.get('device', 0))
|
||||
scan_rf = params.get('rf', True)
|
||||
wifi_interface = params.get('wifi_interface') or params.get('interface')
|
||||
bt_adapter = params.get('bt_interface') or params.get('adapter', 'hci0')
|
||||
sdr_device = params.get('sdr_device', params.get('device', 0))
|
||||
sweep_type = params.get('sweep_type')
|
||||
|
||||
# Get baseline_id for comparison (same as local mode)
|
||||
baseline_id = params.get('baseline_id')
|
||||
@@ -3129,11 +3130,11 @@ class ModeManager:
|
||||
started_scans = []
|
||||
|
||||
# Start the combined TSCM scanner thread using existing Intercept functions
|
||||
thread = threading.Thread(
|
||||
target=self._tscm_scanner_thread,
|
||||
args=(scan_wifi, scan_bt, scan_rf, wifi_interface, bt_adapter, sdr_device, baseline_id),
|
||||
daemon=True
|
||||
)
|
||||
thread = threading.Thread(
|
||||
target=self._tscm_scanner_thread,
|
||||
args=(scan_wifi, scan_bt, scan_rf, wifi_interface, bt_adapter, sdr_device, baseline_id, sweep_type),
|
||||
daemon=True
|
||||
)
|
||||
thread.start()
|
||||
self.output_threads['tscm'] = thread
|
||||
|
||||
@@ -3152,9 +3153,9 @@ class ModeManager:
|
||||
'scanning': started_scans
|
||||
}
|
||||
|
||||
def _tscm_scanner_thread(self, scan_wifi: bool, scan_bt: bool, scan_rf: bool,
|
||||
wifi_interface: str | None, bt_adapter: str, sdr_device: int,
|
||||
baseline_id: int | None = None):
|
||||
def _tscm_scanner_thread(self, scan_wifi: bool, scan_bt: bool, scan_rf: bool,
|
||||
wifi_interface: str | None, bt_adapter: str, sdr_device: int,
|
||||
baseline_id: int | None = None, sweep_type: str | None = None):
|
||||
"""Combined TSCM scanner using existing Intercept functions.
|
||||
|
||||
NOTE: This matches local mode behavior exactly:
|
||||
@@ -3167,11 +3168,20 @@ class ModeManager:
|
||||
stop_event = self.stop_events.get(mode)
|
||||
|
||||
# Import existing Intercept TSCM functions
|
||||
from routes.tscm import _scan_wifi_networks, _scan_bluetooth_devices, _scan_rf_signals
|
||||
logger.info("TSCM imports successful")
|
||||
|
||||
# Load baseline if specified (same as local mode)
|
||||
baseline = None
|
||||
from routes.tscm import _scan_wifi_networks, _scan_bluetooth_devices, _scan_rf_signals
|
||||
logger.info("TSCM imports successful")
|
||||
|
||||
sweep_ranges = None
|
||||
if sweep_type:
|
||||
try:
|
||||
from data.tscm_frequencies import get_sweep_preset, SWEEP_PRESETS
|
||||
preset = get_sweep_preset(sweep_type) or SWEEP_PRESETS.get('standard')
|
||||
sweep_ranges = preset.get('ranges') if preset else None
|
||||
except Exception:
|
||||
sweep_ranges = None
|
||||
|
||||
# Load baseline if specified (same as local mode)
|
||||
baseline = None
|
||||
if baseline_id and HAS_BASELINE_DB and get_tscm_baseline:
|
||||
baseline = get_tscm_baseline(baseline_id)
|
||||
if baseline:
|
||||
@@ -3239,15 +3249,18 @@ class ModeManager:
|
||||
enriched['is_new'] = not classification.get('in_baseline', False)
|
||||
enriched['reasons'] = classification.get('reasons', [])
|
||||
|
||||
if self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_wifi_device(enriched)
|
||||
enriched['classification'] = profile.risk_level.value
|
||||
enriched['score'] = profile.total_score
|
||||
enriched['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
enriched['recommended_action'] = profile.recommended_action
|
||||
if self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_wifi_device(enriched)
|
||||
enriched['classification'] = profile.risk_level.value
|
||||
enriched['score'] = profile.total_score
|
||||
enriched['score_modifier'] = profile.score_modifier
|
||||
enriched['known_device'] = profile.known_device
|
||||
enriched['known_device_name'] = profile.known_device_name
|
||||
enriched['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
enriched['recommended_action'] = profile.recommended_action
|
||||
|
||||
self.wifi_networks[bssid] = enriched
|
||||
except Exception as e:
|
||||
@@ -3285,15 +3298,18 @@ class ModeManager:
|
||||
enriched['is_new'] = not classification.get('in_baseline', False)
|
||||
enriched['reasons'] = classification.get('reasons', [])
|
||||
|
||||
if self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_bluetooth_device(enriched)
|
||||
enriched['classification'] = profile.risk_level.value
|
||||
enriched['score'] = profile.total_score
|
||||
enriched['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
enriched['recommended_action'] = profile.recommended_action
|
||||
if self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_bluetooth_device(enriched)
|
||||
enriched['classification'] = profile.risk_level.value
|
||||
enriched['score'] = profile.total_score
|
||||
enriched['score_modifier'] = profile.score_modifier
|
||||
enriched['known_device'] = profile.known_device
|
||||
enriched['known_device_name'] = profile.known_device_name
|
||||
enriched['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
enriched['recommended_action'] = profile.recommended_action
|
||||
|
||||
self.bluetooth_devices[mac] = enriched
|
||||
except Exception as e:
|
||||
@@ -3304,7 +3320,11 @@ class ModeManager:
|
||||
try:
|
||||
# Pass a stop check that uses our stop_event (not the module's _sweep_running)
|
||||
agent_stop_check = lambda: stop_event and stop_event.is_set()
|
||||
rf_signals = _scan_rf_signals(sdr_device, stop_check=agent_stop_check)
|
||||
rf_signals = _scan_rf_signals(
|
||||
sdr_device,
|
||||
stop_check=agent_stop_check,
|
||||
sweep_ranges=sweep_ranges
|
||||
)
|
||||
|
||||
# Analyze each RF signal like local mode does
|
||||
analyzed_signals = []
|
||||
@@ -3324,14 +3344,17 @@ class ModeManager:
|
||||
analyzed['reasons'] = classification.get('reasons', [])
|
||||
|
||||
# Use correlation engine for scoring (same as local mode)
|
||||
if hasattr(self, '_tscm_correlation') and self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_rf_signal(signal)
|
||||
analyzed['classification'] = profile.risk_level.value
|
||||
analyzed['score'] = profile.total_score
|
||||
analyzed['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
if hasattr(self, '_tscm_correlation') and self._tscm_correlation:
|
||||
profile = self._tscm_correlation.analyze_rf_signal(signal)
|
||||
analyzed['classification'] = profile.risk_level.value
|
||||
analyzed['score'] = profile.total_score
|
||||
analyzed['score_modifier'] = profile.score_modifier
|
||||
analyzed['known_device'] = profile.known_device
|
||||
analyzed['known_device_name'] = profile.known_device_name
|
||||
analyzed['indicators'] = [
|
||||
{'type': i.type.value, 'desc': i.description}
|
||||
for i in profile.indicators
|
||||
]
|
||||
|
||||
analyzed['is_threat'] = is_threat
|
||||
analyzed_signals.append(analyzed)
|
||||
|
||||
Reference in New Issue
Block a user