worked poc

This commit is contained in:
Mateusz Gruszczyński
2026-08-14 11:33:01 +02:00
parent adfdb0b86c
commit fc3a2944b2
94 changed files with 2931 additions and 3412 deletions
+33 -2
View File
@@ -10,6 +10,7 @@ from .policy import PolicyEngine
from .routeros import RouterOSClient
from .state import RuntimeStats
from .store import AlertStore
from .tuning import AlertTuner
class EVEWatcher(threading.Thread):
@@ -17,20 +18,25 @@ class EVEWatcher(threading.Thread):
self,
path: str,
store: AlertStore,
tuner: AlertTuner,
policy: PolicyEngine,
routeros: RouterOSClient,
block_timeout: str,
dedup_window_seconds: int,
stats: RuntimeStats,
stop_event: threading.Event,
) -> None:
super().__init__(name="eve-watcher", daemon=True)
self.path = path
self.store = store
self.tuner = tuner
self.policy = policy
self.routeros = routeros
self.block_timeout = block_timeout
self.dedup_window_seconds = max(0, int(dedup_window_seconds))
self.stats = stats
self.stop_event = stop_event
self._initial_seek_done = False
def run(self) -> None:
while not self.stop_event.is_set():
@@ -45,7 +51,12 @@ class EVEWatcher(threading.Thread):
def _follow_file(self) -> None:
with open(self.path, "r", encoding="utf-8", errors="replace") as handle:
handle.seek(0, os.SEEK_END)
# Ignore historical EVE only on the first attach. After rotation or
# truncation read the replacement file from byte 0 so alerts that
# arrived during the hand-off are not skipped.
if not self._initial_seek_done:
handle.seek(0, os.SEEK_END)
self._initial_seek_done = True
inode = os.fstat(handle.fileno()).st_ino
print(f"[eve] following {self.path}", flush=True)
@@ -71,11 +82,31 @@ class EVEWatcher(threading.Thread):
return
self.stats.inc("eve_events")
if event.get("event_type") != "alert":
event_type = event.get("event_type")
if event_type == "stats":
raw_stats = event.get("stats")
if isinstance(raw_stats, dict):
self.stats.update_suricata(raw_stats, str(event.get("timestamp") or ""))
return
if event_type != "alert":
return
self.stats.inc("eve_alerts")
self.stats.stamp("last_alert_at")
tuning = self.tuner.evaluate(event)
if not tuning.keep:
self.stats.inc("alerts_filtered")
key = f"alerts_filtered_{tuning.reason}"
self.stats.inc(key)
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")
return
decision = self.policy.evaluate(event)
blocked = False
reason = decision.reason