v.0.11.4
This commit is contained in:
+24
-8
@@ -21,6 +21,7 @@ SUPPORTED_EVENT_TYPES = {
|
||||
"ssh", "rdp", "smb", "quic", "dhcp", "arp", "ike", "mqtt", "ftp", "ftp_data", "smtp",
|
||||
"websocket", "nfs", "tftp", "dcerpc", "krb5", "snmp", "rfb", "sip", "ldap", "pop3",
|
||||
}
|
||||
MAX_ANALYTICS_DIMENSION_KEYS = 4096
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
@@ -52,6 +53,20 @@ def _text(value: Any, max_len: int = 512) -> str:
|
||||
return str(value)[:max_len]
|
||||
|
||||
|
||||
def _bounded_counter_add(
|
||||
counter: collections.Counter[str],
|
||||
key: str,
|
||||
amount: int = 1,
|
||||
*,
|
||||
max_keys: int = MAX_ANALYTICS_DIMENSION_KEYS,
|
||||
) -> None:
|
||||
"""Update a dashboard Counter without retaining unbounded unique values."""
|
||||
if not key:
|
||||
return
|
||||
if key in counter or len(counter) < max_keys:
|
||||
counter[key] += amount
|
||||
|
||||
|
||||
def _parse_networks(value: str) -> list[ipaddress._BaseNetwork]:
|
||||
result: list[ipaddress._BaseNetwork] = []
|
||||
for raw in (value or "").split(","):
|
||||
@@ -1215,7 +1230,8 @@ class TrafficHistory:
|
||||
|
||||
def _trim_if_due(self, redis: RedisConnection) -> None:
|
||||
now = time.monotonic()
|
||||
if now - self._last_trim > 15:
|
||||
interval = 1.0 if self.max_events > 0 else 15.0
|
||||
if now - self._last_trim > interval:
|
||||
self._trim(redis)
|
||||
self._last_trim = now
|
||||
|
||||
@@ -1437,7 +1453,7 @@ class _AnalyticsAccumulator:
|
||||
self.alerts += 1
|
||||
signature = _text(item.get("signature"), 160)
|
||||
if signature:
|
||||
self.signatures[signature] += 1
|
||||
_bounded_counter_add(self.signatures, signature)
|
||||
severity = item.get("severity")
|
||||
if severity not in (None, ""):
|
||||
self.severities[f"S{severity}"] += 1
|
||||
@@ -1451,26 +1467,26 @@ class _AnalyticsAccumulator:
|
||||
self.files += 1
|
||||
filename = _text(item.get("filename"), 180) or "unnamed file"
|
||||
digest = _text(item.get("file_sha256") or item.get("file_sha1") or item.get("file_md5"), 32)
|
||||
self.file_activity[f"{filename}{' · ' + digest if digest else ''}"] += 1
|
||||
_bounded_counter_add(self.file_activity, f"{filename}{' · ' + digest if digest else ''}")
|
||||
direction = _text(item.get("direction"), 24) or "unknown"
|
||||
src_ip = _text(item.get("src_ip"), 64)
|
||||
dest_ip = _text(item.get("dest_ip"), 64)
|
||||
ether_src = _text(item.get("ether_src"), 32)
|
||||
ether_dest = _text(item.get("ether_dest"), 32)
|
||||
if direction in {"outbound", "internal"} and src_ip and ether_src:
|
||||
self.assets[f"{src_ip} · {ether_src}"] += 1
|
||||
_bounded_counter_add(self.assets, f"{src_ip} · {ether_src}")
|
||||
if direction in {"inbound", "internal"} and dest_ip and ether_dest:
|
||||
self.assets[f"{dest_ip} · {ether_dest}"] += 1
|
||||
_bounded_counter_add(self.assets, f"{dest_ip} · {ether_dest}")
|
||||
if item.get("type") == "dhcp":
|
||||
asset_ip = _text(item.get("dhcp_assigned_ip") or item.get("src_ip"), 64)
|
||||
identity = _text(item.get("dhcp_hostname") or item.get("dhcp_client_mac"), 160)
|
||||
if asset_ip or identity:
|
||||
self.assets[f"{asset_ip}{' · ' if asset_ip and identity else ''}{identity}"] += 1
|
||||
_bounded_counter_add(self.assets, f"{asset_ip}{' · ' if asset_ip and identity else ''}{identity}")
|
||||
elif item.get("type") == "arp":
|
||||
asset_ip = _text(item.get("arp_src_ip") or item.get("src_ip"), 64)
|
||||
mac = _text(item.get("arp_src_mac"), 32)
|
||||
if asset_ip or mac:
|
||||
self.assets[f"{asset_ip}{' · ' if asset_ip and mac else ''}{mac}"] += 1
|
||||
_bounded_counter_add(self.assets, f"{asset_ip}{' · ' if asset_ip and mac else ''}{mac}")
|
||||
app_proto = _valid_app_proto(item.get("app_proto"))
|
||||
if item.get("type") in {"tls", "quic", "ssh"} or app_proto in {"tls", "quic", "ssh"}:
|
||||
self.encrypted += 1
|
||||
@@ -1484,7 +1500,7 @@ class _AnalyticsAccumulator:
|
||||
):
|
||||
value = _text(item.get(key), 160)
|
||||
if value:
|
||||
self.fingerprints[f"{label} {value}"] += 1
|
||||
_bounded_counter_add(self.fingerprints, f"{label} {value}")
|
||||
if item.get("type") in {"http", "ftp", "smtp"} or app_proto in {"http", "ftp", "smtp", "telnet"}:
|
||||
self.cleartext += 1
|
||||
if is_flow:
|
||||
|
||||
Reference in New Issue
Block a user