- 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>
All config/data paths now use /etc/xdp-defense/ consistently,
eliminating the legacy xdp-blocker directory reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add weekend profile and raise night/default PPS to match business hours,
as the server can be busy at any time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
Daemon fixes:
- Add _db_lock for thread-safe SQLite access
- Atomic SIGHUP config swap (build all values before applying)
- Check world-writable permission before loading pickle model
- Write model files with 0o600 permissions via os.open
- Module-level xdp_common import with fatal exit on failure
- Close traffic DB on shutdown
- Add period_data parameter to _train() to avoid race condition
CLI fixes:
- Replace $COMMON_PY variable with hardcoded 'xdp_common'
- Pass CONFIG_FILE via sys.argv instead of string interpolation
- Add key_hex regex validation before all bpftool commands
- Switch sanitize_input from denylist to strict allowlist
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split single IsolationForest into 4 period models (night/morning/afternoon/evening)
- Each period trained independently on its time window data
- Filter attack samples during retrain using existing model scores (threshold -0.5)
- Retrain runs in background thread with lock, inference continues uninterrupted
- New pickle format 'period_models' with automatic old format detection
- SIGUSR1 and auto-retrain both use background mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- traffic_log.csv → traffic_log.db (SQLite with indexed timestamp)
- INSERT instead of CSV append, DELETE instead of file rewrite
- CLI queries use SQL (GROUP BY for traffic, LIMIT for log)
- retrain_from_log() uses read-only connection with time range query
- Config key: traffic_log_file → traffic_log_db
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log traffic features with timestamps to CSV every 5s
- Add hour_sin/hour_cos time features (15 → 17 feature vector)
- Auto-retrain from traffic log at configurable interval (default 24h)
- Detect old 15-feature models and switch to learning mode
- SIGUSR1 now retrains from traffic log first, falls back to collect mode
- Add CLI: `ai traffic` (time-bucketed summary), `ai log` (recent entries)
- Add config keys: traffic_log_file, retention_days, retrain_window
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously whitelist only accepted named presets (cloudflare, aws, etc).
Now `xdp-defense whitelist add 8.8.8.8/32` works directly for both
IPv4 and IPv6 addresses, writing to the shared pinned BPF map.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Chain two XDP programs via libxdp dispatcher on the same interface:
xdp_blocker (priority 10) handles CIDR/country/whitelist blocking,
xdp_ddos (priority 20) handles rate limiting, EWMA analysis, and AI
anomaly detection. Whitelist maps are shared via BPF map pinning so
whitelisted IPs bypass both blocklist checks and DDoS rate limiting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>