Fix module subprocess lifecycle and capture_bus injection bugs
Three bugs causing all modules to exit within seconds of startup: 1. _module_runner had no keep-alive loop after calling module.start(). All modules use a thread-spawning pattern where start() returns immediately, so the subprocess exited and killed all daemon threads. Added while module._running: sleep(1) loop to block until stop(). 2. Engine injected capture_bus under key 'capture_bus' but 9 modules (auth_flow_tracker, cloud_token_harvester, ldap_harvester, network_mapper, rdp_monitor, quic_analyzer, smb_monitor, db_interceptor, vlan_discovery) look for '_capture_bus'. Inject both keys so all modules get it. 3. mac_manager crashes on startup when innocuous_macs.db exists but has no mac_profiles table (DB not yet seeded). Added OperationalError handler to fall back to random OUI instead of crashing.
This commit is contained in:
@@ -192,11 +192,18 @@ def _module_runner(module_class: Type[BaseModule], bus_queue: multiprocessing.Qu
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
module.start()
|
module.start()
|
||||||
|
# start() is non-blocking — keep subprocess alive while module threads run
|
||||||
|
while module._running:
|
||||||
|
time.sleep(1)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Module %s crashed in start()", module.name)
|
logger.exception("Module %s crashed in start()", module.name)
|
||||||
bus_proxy.emit("MODULE_ERROR", {"module": module.name, "error": "start_crash"},
|
bus_proxy.emit("MODULE_ERROR", {"module": module.name, "error": "start_crash"},
|
||||||
source_module=module.name)
|
source_module=module.name)
|
||||||
finally:
|
finally:
|
||||||
|
try:
|
||||||
|
module.stop()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
state.stop()
|
state.stop()
|
||||||
|
|
||||||
|
|
||||||
@@ -357,9 +364,11 @@ class Engine:
|
|||||||
self.capture_bus = None
|
self.capture_bus = None
|
||||||
|
|
||||||
# Inject capture_bus into module configs for passive modules
|
# Inject capture_bus into module configs for passive modules
|
||||||
|
# Some modules use "capture_bus", others "_capture_bus" — inject both
|
||||||
for name, entry in self._modules.items():
|
for name, entry in self._modules.items():
|
||||||
if getattr(entry.module_class, "requires_capture_bus", False):
|
if getattr(entry.module_class, "requires_capture_bus", False):
|
||||||
entry.config["capture_bus"] = self.capture_bus
|
entry.config["capture_bus"] = self.capture_bus
|
||||||
|
entry.config["_capture_bus"] = self.capture_bus
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
for name in order:
|
for name in order:
|
||||||
|
|||||||
@@ -210,6 +210,9 @@ class MacManager(BaseModule):
|
|||||||
if rows:
|
if rows:
|
||||||
return dict(random.choice(rows))
|
return dict(random.choice(rows))
|
||||||
return None
|
return None
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.warning("mac_profiles table missing — DB not seeded, using fallback")
|
||||||
|
return None
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user