test ebpf
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 1m40s

This commit is contained in:
2026-03-07 10:06:24 +01:00
parent a98054cb5b
commit f9bbe9b73c
13 changed files with 1271 additions and 177 deletions

View File

@@ -0,0 +1,128 @@
"""Manage the eBPF telemetry subprocess used for bridge direction and verdict events."""
from __future__ import annotations
import json
import logging
import os
import signal
import subprocess
import sys
import threading
from pathlib import Path
from typing import Iterable, Optional
from src.utilities.packet_tracker import packet_tracker
logger = logging.getLogger("bridge_telemetry")
class BridgeTelemetryManager:
"""Run a single eBPF collector process for the active sniffed interfaces."""
def __init__(self) -> None:
self._interfaces: set[str] = set()
self._process: Optional[subprocess.Popen[str]] = None
self._reader_thread: Optional[threading.Thread] = None
self._lock = threading.Lock()
def update_interfaces(self, interfaces: Iterable[str]) -> None:
"""Restart the collector when the active interface set changes."""
normalized = {iface.strip() for iface in interfaces if iface and iface.strip()}
with self._lock:
if normalized == self._interfaces:
return
self._interfaces = normalized
self._restart_locked()
def stop(self) -> None:
"""Stop the collector process and reader thread."""
with self._lock:
self._interfaces = set()
self._stop_process_locked()
def _restart_locked(self) -> None:
self._stop_process_locked()
if not self._interfaces:
return
helper = Path(__file__).with_name("ebpf_bridge_events.py")
python_bin = sys.executable or "python3"
if "venv" in python_bin:
python_bin = "python3"
env = os.environ.copy()
env["PYTHONUNBUFFERED"] = "1"
cmd = [python_bin, str(helper), "--ifaces", ",".join(sorted(self._interfaces))]
logger.info("Starting bridge telemetry collector for interfaces=%s", sorted(self._interfaces))
try:
self._process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
env=env,
)
except Exception:
logger.exception("Failed to start bridge telemetry collector")
self._process = None
return
self._reader_thread = threading.Thread(
target=self._read_loop,
args=(self._process,),
daemon=True,
name="bridge-telemetry-reader",
)
self._reader_thread.start()
def _stop_process_locked(self) -> None:
process = self._process
reader = self._reader_thread
self._process = None
self._reader_thread = None
if process is not None and process.poll() is None:
try:
process.send_signal(signal.SIGTERM)
process.wait(timeout=3)
except subprocess.TimeoutExpired:
process.kill()
except Exception:
logger.exception("Failed to stop bridge telemetry collector cleanly")
if reader is not None and reader.is_alive():
reader.join(timeout=2)
def _read_loop(self, process: subprocess.Popen[str]) -> None:
stdout = process.stdout
if stdout is None:
return
for line in stdout:
text = line.strip()
if not text:
continue
try:
event = json.loads(text)
except json.JSONDecodeError:
logger.info("bridge-telemetry: %s", text)
continue
if "event_type" not in event:
logger.info("bridge-telemetry: %s", event)
continue
try:
packet_tracker.observe_telemetry(event)
except Exception:
logger.exception("Failed to process telemetry event: %s", event)
rc = process.poll()
if rc not in (0, None):
logger.warning("Bridge telemetry collector exited with code %s", rc)
bridge_telemetry_manager = BridgeTelemetryManager()