Add CDN filter and fix xdp-cdn-update bugs

- Add xdp_cdn_filter BPF program (priority 5) to allow only CDN/whitelist on port 80/443
- Fix \r carriage return bug preventing BunnyCDN IPv4 loading (594 IPs were silently failing)
- Fix BPF map flush code to handle list-type keys from bpftool JSON output
- Fix per-cpu stats parsing to use formatted values from bpftool
- Replace in-loop counter with post-load BPF map verification for accurate counts
- Remove xdp_cdn_load.py (consolidated into xdp-cdn-update)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kaffa
2026-02-15 11:03:14 +09:00
parent 0ef77e2f7c
commit 5adafcd099
5 changed files with 522 additions and 24 deletions

View File

@@ -631,6 +631,9 @@ class DDoSDaemon:
self._last_retrain_time = self._get_model_mtime()
self._last_log_cleanup = time.time()
self._blocked_ips = set()
self._blocked_ips_lock = threading.Lock()
self._init_traffic_db()
level = self.cfg['general'].get('log_level', 'info').upper()
@@ -830,19 +833,33 @@ class DDoSDaemon:
)
if level == 'temp_block':
dur = self.cfg['escalation'].get('temp_block_duration', 300)
try:
block_ip(ip_str, dur)
log.warning("TEMP BLOCK: %s for %ds", ip_str, dur)
except Exception as e:
log.error("Failed to temp-block %s: %s", ip_str, e)
with self._blocked_ips_lock:
already = ip_str in self._blocked_ips
if already:
log.debug("EWMA skip (already blocked): %s", ip_str)
else:
dur = self.cfg['escalation'].get('temp_block_duration', 300)
try:
block_ip(ip_str, dur)
with self._blocked_ips_lock:
self._blocked_ips.add(ip_str)
log.warning("TEMP BLOCK: %s for %ds", ip_str, dur)
except Exception as e:
log.error("Failed to temp-block %s: %s", ip_str, e)
elif level == 'perm_block':
try:
block_ip(ip_str, 0)
log.warning("PERM BLOCK: %s", ip_str)
except Exception as e:
log.error("Failed to perm-block %s: %s", ip_str, e)
with self._blocked_ips_lock:
already = ip_str in self._blocked_ips
if already:
log.debug("EWMA skip (already blocked): %s", ip_str)
else:
try:
block_ip(ip_str, 0)
with self._blocked_ips_lock:
self._blocked_ips.add(ip_str)
log.warning("PERM BLOCK: %s", ip_str)
except Exception as e:
log.error("Failed to perm-block %s: %s", ip_str, e)
self.ewma_analyzer.cleanup_stale(active_ips)
@@ -970,19 +987,33 @@ class DDoSDaemon:
log.warning("AI escalation: %s ewma=%.1f baseline=%.1f -> %s", ip_str, ewma, baseline, level)
if level == 'temp_block':
dur = self.cfg['escalation'].get('temp_block_duration', 300)
try:
block_ip(ip_str, dur)
log.warning("AI TEMP BLOCK: %s for %ds", ip_str, dur)
except Exception as e:
log.error("Failed to AI temp-block %s: %s", ip_str, e)
with self._blocked_ips_lock:
already = ip_str in self._blocked_ips
if already:
log.debug("AI skip (already blocked): %s", ip_str)
else:
dur = self.cfg['escalation'].get('temp_block_duration', 300)
try:
block_ip(ip_str, dur)
with self._blocked_ips_lock:
self._blocked_ips.add(ip_str)
log.warning("AI TEMP BLOCK: %s for %ds", ip_str, dur)
except Exception as e:
log.error("Failed to AI temp-block %s: %s", ip_str, e)
elif level == 'perm_block':
try:
block_ip(ip_str, 0)
log.warning("AI PERM BLOCK: %s", ip_str)
except Exception as e:
log.error("Failed to AI perm-block %s: %s", ip_str, e)
with self._blocked_ips_lock:
already = ip_str in self._blocked_ips
if already:
log.debug("AI skip (already blocked): %s", ip_str)
else:
try:
block_ip(ip_str, 0)
with self._blocked_ips_lock:
self._blocked_ips.add(ip_str)
log.warning("AI PERM BLOCK: %s", ip_str)
except Exception as e:
log.error("Failed to AI perm-block %s: %s", ip_str, e)
prev_features = features
@@ -1014,6 +1045,8 @@ class DDoSDaemon:
try:
unblock_ip(ip_str)
self.violation_tracker.clear(ip_str)
with self._blocked_ips_lock:
self._blocked_ips.discard(ip_str)
log.info("Expired block removed: %s (dropped %d pkts)", ip_str, drop_count)
except Exception as e:
log.error("Failed to remove expired block %s: %s", ip_str, e)