poc2_worked

This commit is contained in:
Mateusz Gruszczyński
2026-08-15 18:29:36 +02:00
parent fc3a2944b2
commit 71b6c0d86f
62 changed files with 9112 additions and 375 deletions
+30 -1
View File
@@ -6,6 +6,8 @@ import threading
import time
from typing import Any
from .live import LiveEventPipeline, TrafficNormalizer, is_dashboard_noise
from .ndr import NDRAnalyzer
from .policy import PolicyEngine
from .routeros import RouterOSClient
from .state import RuntimeStats
@@ -25,6 +27,9 @@ class EVEWatcher(threading.Thread):
dedup_window_seconds: int,
stats: RuntimeStats,
stop_event: threading.Event,
normalizer: TrafficNormalizer | None = None,
live_pipeline: LiveEventPipeline | None = None,
ndr_analyzer: NDRAnalyzer | None = None,
) -> None:
super().__init__(name="eve-watcher", daemon=True)
self.path = path
@@ -36,6 +41,9 @@ class EVEWatcher(threading.Thread):
self.dedup_window_seconds = max(0, int(dedup_window_seconds))
self.stats = stats
self.stop_event = stop_event
self.normalizer = normalizer
self.live_pipeline = live_pipeline
self.ndr_analyzer = ndr_analyzer
self._initial_seek_done = False
def run(self) -> None:
@@ -88,7 +96,9 @@ class EVEWatcher(threading.Thread):
if isinstance(raw_stats, dict):
self.stats.update_suricata(raw_stats, str(event.get("timestamp") or ""))
return
if event_type != "alert":
self._publish_live(event)
return
self.stats.inc("eve_alerts")
@@ -99,12 +109,15 @@ class EVEWatcher(threading.Thread):
self.stats.inc("alerts_filtered")
key = f"alerts_filtered_{tuning.reason}"
self.stats.inc(key)
# A filtered alert is deliberately excluded from the dashboard and
# Redis traffic history. The original EVE record stays on disk.
return
duplicate_id = self.store.find_recent_duplicate(event, self.dedup_window_seconds)
if duplicate_id is not None:
self.store.bump_duplicate(duplicate_id, event)
self.stats.inc("alerts_deduplicated")
self._publish_live(event, deduplicated=True, incident_id=duplicate_id)
return
decision = self.policy.evaluate(event)
@@ -125,4 +138,20 @@ class EVEWatcher(threading.Thread):
reason = result.message if result.success else f"{decision.reason}; {result.message}"
self.stats.inc("block_success" if result.success else "block_errors")
self.store.insert_alert(event, blocked, decision.target, reason)
incident_id = self.store.insert_alert(event, blocked, decision.target, reason)
self._publish_live(
event,
blocked=blocked,
block_target=decision.target,
block_reason=reason,
incident_id=incident_id,
)
def _publish_live(self, event: dict[str, Any], **extra: Any) -> None:
if self.normalizer is None or self.live_pipeline is None:
return
record = self.normalizer.normalize(event, **extra)
if record is not None and not is_dashboard_noise(record):
if self.ndr_analyzer is not None:
self.ndr_analyzer.observe(record, int(extra["incident_id"]) if extra.get("incident_id") is not None else None)
self.live_pipeline.publish(record)