add dynamic

This commit is contained in:
larssand
2026-06-18 21:48:32 +02:00
parent e45603eed7
commit 0e42e42c53
3 changed files with 70 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ import sys
from pathlib import Path
from .llm import ollama_summary
from .logs import read_events, summarize_events
from .logs import local_in_failures, read_events, summarize_events, top_field_values
from .mitigation import FortiGateClient, parse_allowlist, suggest_block_candidates
from .policies import audit_policies, read_policies
from .syslog_server import listen_udp_syslog
@@ -27,6 +27,13 @@ def analyze_logs(args: argparse.Namespace) -> int:
_print_json(
{
"summary": summarize_events(events),
"diagnostics": {
"top_source_ips": top_field_values(events, "srcip", limit=10),
"top_services": top_field_values(events, "service", limit=10),
"top_actions": top_field_values(events, "action", limit=10),
"top_subtypes": top_field_values(events, "subtype", limit=10),
"local_in_failures": local_in_failures(events, limit=10),
},
"block_candidates": [
{"src_ip": candidate.src_ip, "score": candidate.score, "reasons": candidate.reasons}
for candidate in candidates

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
import json
import shlex
from collections import Counter
from collections.abc import Iterable
from pathlib import Path
@@ -117,3 +118,29 @@ def summarize_events(events: Iterable[LogEvent]) -> dict[str, int]:
if event.severity in {"critical", "high", "alert", "emergency"}:
summary["critical_or_high"] += 1
return summary
def top_field_values(events: Iterable[LogEvent], field: str, *, limit: int = 10) -> list[dict[str, int | str]]:
counter: Counter[str] = Counter()
for event in events:
value = event.fields.get(field)
if value:
counter[value] += 1
return [{"value": value, "count": count} for value, count in counter.most_common(limit)]
def local_in_failures(events: Iterable[LogEvent], *, limit: int = 10) -> list[dict[str, int | str]]:
counter: Counter[tuple[str, str, str]] = Counter()
for event in events:
policy_type = event.fields.get("policytype", event.fields.get("type", "")).lower()
msg = event.fields.get("msg", "").lower()
if not (policy_type.startswith("local-in") or "local-in" in policy_type or msg == "connection failed"):
continue
src_ip = event.src_ip or "unknown"
service = event.fields.get("service", event.fields.get("app", "unknown"))
policy_id = event.fields.get("policyid", event.fields.get("poluuid", "unknown"))
counter[(src_ip, service, policy_id)] += 1
return [
{"src_ip": src_ip, "service": service, "policy": policy_id, "count": count}
for (src_ip, service, policy_id), count in counter.most_common(limit)
]