Reduce EWMA false positives with min_pps threshold

- Add min_pps (default 20) to skip anomaly detection for low-traffic IPs
- Increase threshold_multiplier from 3.0 to 5.0
- Increase rate_limit_after from 1 to 3 violations
- Support min_pps in SIGHUP config reload

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kaffa
2026-02-07 14:32:41 +09:00
parent e994a0a63a
commit 1c2c94d36a
2 changed files with 15 additions and 6 deletions

View File

@@ -79,7 +79,8 @@ DEFAULT_CONFIG = {
'ewma': {
'alpha': 0.3,
'poll_interval': 1,
'threshold_multiplier': 3.0,
'threshold_multiplier': 5.0,
'min_pps': 20,
},
'ai': {
'enabled': True,
@@ -170,9 +171,10 @@ class ViolationTracker:
class EWMAAnalyzer:
"""Per-IP EWMA calculation for rate anomaly detection."""
def __init__(self, alpha=0.3, threshold_multiplier=3.0):
def __init__(self, alpha=0.3, threshold_multiplier=5.0, min_pps=20):
self.alpha = alpha
self.threshold_multiplier = threshold_multiplier
self.min_pps = min_pps
self.ewma = {}
self.baseline = {}
self.lock = threading.Lock()
@@ -188,6 +190,9 @@ class EWMAAnalyzer:
self.ewma[ip] = self.alpha * current_pps + (1 - self.alpha) * self.ewma[ip]
self.baseline[ip] = 0.01 * current_pps + 0.99 * self.baseline[ip]
if current_pps < self.min_pps:
return False
base = max(self.baseline[ip], 1)
if self.ewma[ip] > base * self.threshold_multiplier:
return True
@@ -614,7 +619,8 @@ class DDoSDaemon:
self.violation_tracker = ViolationTracker(self.cfg['escalation'])
self.ewma_analyzer = EWMAAnalyzer(
alpha=self.cfg['ewma'].get('alpha', 0.3),
threshold_multiplier=self.cfg['ewma'].get('threshold_multiplier', 3.0),
threshold_multiplier=self.cfg['ewma'].get('threshold_multiplier', 5.0),
min_pps=self.cfg['ewma'].get('min_pps', 20),
)
self.ai_detector = AIDetector(self.cfg['ai'])
self.profile_manager = ProfileManager(self.cfg['rate_limits'])
@@ -673,7 +679,8 @@ class DDoSDaemon:
# Build all new values before swapping anything
new_escalation = new_cfg['escalation']
new_alpha = new_cfg['ewma'].get('alpha', 0.3)
new_threshold = new_cfg['ewma'].get('threshold_multiplier', 3.0)
new_threshold = new_cfg['ewma'].get('threshold_multiplier', 5.0)
new_min_pps = new_cfg['ewma'].get('min_pps', 20)
new_ai_cfg = new_cfg['ai']
new_rate_cfg = new_cfg['rate_limits']
new_ewma_interval = new_cfg['ewma'].get('poll_interval', 1)
@@ -684,6 +691,7 @@ class DDoSDaemon:
self.violation_tracker.cfg = new_escalation
self.ewma_analyzer.alpha = new_alpha
self.ewma_analyzer.threshold_multiplier = new_threshold
self.ewma_analyzer.min_pps = new_min_pps
self.ai_detector.cfg = new_ai_cfg
self.profile_manager.cfg = new_rate_cfg
self._ewma_interval = new_ewma_interval