#!/usr/bin/env python3 """Flagging rules for the intrusion-detection system. Detection functions that identify hostile IPs based on aggregated stats. """ from __future__ import annotations import bad_patterns from models import IPStats def flag_scanners(stats: dict[str, IPStats], min_errors: int = 5, min_ratio: float = 0.5) -> dict[str, IPStats]: """IPs with many errors AND a high error ratio.""" return { ip: s for ip, s in stats.items() if s.errors >= min_errors and s.error_ratio >= min_ratio } def flag_denied_only(stats: dict[str, IPStats], min_denied: int = 1) -> dict[str, IPStats]: """IPs that only ever hit denied paths and never authenticated.""" return { ip: s for ip, s in stats.items() if s.denied >= min_denied and not s.authenticated } def flag_malicious_patterns(stats: dict[str, IPStats], min_severity: int = 2, min_hits: int = 1) -> dict[str, IPStats]: """IPs with hits against malicious path patterns at or above severity threshold.""" return { ip: s for ip, s in stats.items() if s.malicious_hits >= min_hits and any( bad_patterns.PATTERNS_BY_NAME[name].severity >= min_severity for name in s.malicious_patterns ) } def by_total(stats: dict[str, IPStats]) -> list[IPStats]: """Stats sorted by request count, descending.""" return sorted(stats.values(), key=lambda s: (-s.total, s.ip))