This commit is contained in:
larssand
2026-06-21 15:19:24 +02:00
parent d41d318134
commit 5bb381a063
6 changed files with 81 additions and 20 deletions

View File

@@ -35,6 +35,10 @@ class BaselineStore:
denies integer not null, utm integer not null,
primary key (source_ip, bucket_start)
);
create table if not exists source_values (
source_ip text not null, kind text not null, value text not null,
seen_count integer not null, primary key (source_ip, kind, value)
);
"""
)
@@ -59,6 +63,13 @@ class BaselineStore:
values[2] += _number(event.fields.get("hitcount"))
values[3] += int(event.action in THREAT_ACTIONS)
values[4] += int(is_utm_event(event))
for kind, value in (("destination", event.dst_ip), ("destination_port", event.fields.get("dstport"))):
if value:
connection.execute(
"""insert into source_values values (?, ?, ?, 1)
on conflict(source_ip, kind, value) do update set seen_count=seen_count+1""",
(event.src_ip, kind, value),
)
inserted += 1
for (source_ip, bucket), values in pending.items():
connection.execute(
@@ -70,8 +81,8 @@ class BaselineStore:
)
return inserted
def profiles(self, source_ips: set[str]) -> dict[str, dict[str, float | int]]:
profiles: dict[str, dict[str, float | int]] = {}
def profiles(self, source_ips: set[str]) -> dict[str, dict[str, object]]:
profiles: dict[str, dict[str, object]] = {}
with self._connect() as connection:
for source_ip in source_ips:
rows = connection.execute(
@@ -83,9 +94,14 @@ class BaselineStore:
continue
rates = [row[0] * 60 / self.bucket_seconds for row in rows]
hit_rates = [row[2] * 60 / self.bucket_seconds for row in rows]
known = connection.execute(
"select kind, value from source_values where source_ip=?", (source_ip,)
).fetchall()
profiles[source_ip] = {
"samples": len(rows),
"event_rate_mean": mean(rates), "event_rate_stddev": pstdev(rates) or 1.0,
"hitcount_rate_mean": mean(hit_rates), "hitcount_rate_stddev": pstdev(hit_rates) or 1.0,
"known_destinations": [value for kind, value in known if kind == "destination"],
"known_destination_ports": [value for kind, value in known if kind == "destination_port"],
}
return profiles