try nfstream
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 19s

This commit is contained in:
2026-03-07 18:09:38 +01:00
parent 02f76144fa
commit 3ea07bf1df
8 changed files with 613 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ from src.utilities.interface_bridge_helpers import (
from src.config import settings
from src.utilities.bridge_telemetry import bridge_telemetry_manager
from src.utilities.ndpi_classifier import ndpi_classifier
from src.utilities.nfstream_manager import nfstream_manager
from src.utilities.packet_identity import build_packet_uid
from src.utilities.packet_tracker import packet_tracker
from src.Models.etherType import EtherTypeEnum, ethertype_from_int
@@ -162,6 +163,22 @@ def _safe_get_attr(layer, attr: str):
return None
def _merge_enrichment(pkt_info: PacketInfo, enrichment: Dict[str, Any]) -> None:
"""Populate enrichment fields without discarding existing metadata."""
for key, value in enrichment.items():
if value is None:
continue
if key == "dpi_metadata":
current = pkt_info.get("dpi_metadata")
if isinstance(current, dict) and isinstance(value, dict):
pkt_info["dpi_metadata"] = {**current, **value}
elif current is None:
pkt_info["dpi_metadata"] = value
continue
if pkt_info.get(key) is None:
pkt_info[key] = value
def parse_packet(pkt, bridge_label: str, capture_metadata: Optional[Dict[str, Any]] = None) -> None:
"""
Parse a scapy Packet object into a normalized PacketInfo and schedule DB insert.
@@ -355,11 +372,19 @@ def parse_packet(pkt, bridge_label: str, capture_metadata: Optional[Dict[str, An
if Raw in pkt and not pkt_info.get("protocol_name"):
pkt_info["protocol_name"] = "RAW"
# Flow-level enrichment using NFStream, if available.
try:
flow_info = nfstream_manager.lookup_packet(pkt, pkt_iface)
if flow_info:
_merge_enrichment(pkt_info, flow_info)
except Exception:
logger.exception("NFStream enrichment failed")
# Best-effort DPI enrichment using nDPI (optional dependency).
try:
dpi_info = ndpi_classifier.classify_packet(pkt)
if dpi_info:
pkt_info.update(dpi_info)
_merge_enrichment(pkt_info, dpi_info)
except Exception:
logger.exception("nDPI enrichment failed")
@@ -508,6 +533,22 @@ def _sync_bridge_telemetry() -> None:
except Exception:
logger.exception("Failed to update bridge telemetry collector")
active_enrichment_ifaces = sorted(
{
iface
for session in sessions.values()
for iface in (
list(session.get("capture_ifaces", []))
+ (list(session.get("ports", [])) if session.get("is_bridge") else [])
)
if iface
}
)
try:
nfstream_manager.update_interfaces(active_enrichment_ifaces)
except Exception:
logger.exception("Failed to update NFStream enrichment workers")
# -------------------------
# Per-session reader loop
@@ -727,6 +768,10 @@ def stop_afpacket_sniffer(session_id: Optional[str] = None, target: Optional[str
s["ports"].remove(target)
except Exception:
pass
try:
s["capture_ifaces"].remove(target)
except Exception:
pass
logger.info("Removed target %s from session %s", target, sid)
_sync_bridge_telemetry()
return
@@ -803,5 +848,6 @@ def get_internal_debug_state() -> dict:
"buffer_len": len(_PACKET_BUFFER),
"bridge_capture_mode": "tc_ingress_raw" if any(s.get("is_bridge") for s in sessions.values()) else "af_packet",
"telemetry_ports": sorted({iface for session in sessions.values() for iface in session.get("ports", [])}),
"nfstream": nfstream_manager.get_debug_snapshot(),
"packet_tracker": packet_tracker.get_debug_snapshot(),
}