diff --git a/Makefile b/Makefile index 9e141f4..4d1d416 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ INSTALL_BIN := /usr/local/bin SYSTEMD_DIR := /etc/systemd/system ETC_DIR := /etc/xdp-defense DATA_DIR := /var/lib/xdp-defense -BLOCKER_CFG := /etc/xdp-blocker +BLOCKER_CFG := /etc/xdp-defense CLANG ?= clang CLANG_FLAGS := -O2 -g -Wall -target bpf \ @@ -74,7 +74,7 @@ uninstall: rm -f $(INSTALL_BIN)/xdp-defense-daemon rm -f $(SYSTEMD_DIR)/xdp-defense.service systemctl daemon-reload - @echo "Uninstalled. Config preserved in $(ETC_DIR) and $(BLOCKER_CFG)" + @echo "Uninstalled. Config preserved in $(ETC_DIR)" enable: systemctl enable xdp-defense diff --git a/README.md b/README.md index ab3e0a4..058f244 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ general: blocker: enabled: true - config_dir: /etc/xdp-blocker # 블록리스트/국가/화이트리스트 데이터 + config_dir: /etc/xdp-defense # 블록리스트/국가/화이트리스트 데이터 rate_limits: default_pps: 1000 # 초당 패킷 임계값 @@ -224,7 +224,7 @@ ai: └── Makefile /etc/xdp-defense/config.yaml # 런타임 설정 -/etc/xdp-blocker/ # 블록리스트/국가/화이트리스트 데이터 +/etc/xdp-defense/ # 블록리스트/국가/화이트리스트 데이터 /var/lib/xdp-defense/ # PID, AI 모델, 학습 데이터 /sys/fs/bpf/xdp-defense/ # 공유 BPF 맵 핀 경로 ``` diff --git a/bin/xdp-defense b/bin/xdp-defense index 134f9b0..04d1f47 100755 --- a/bin/xdp-defense +++ b/bin/xdp-defense @@ -9,8 +9,8 @@ PIN_PATH="/sys/fs/bpf/xdp-defense" CONFIG_FILE="/etc/xdp-defense/config.yaml" DATA_DIR="/var/lib/xdp-defense" PID_FILE="$DATA_DIR/daemon.pid" -BLOCKLIST_FILE="/etc/xdp-blocker/blocklist.txt" -COUNTRY_DIR="/etc/xdp-blocker/countries" +BLOCKLIST_FILE="/etc/xdp-defense/blocklist.txt" +COUNTRY_DIR="/etc/xdp-defense/countries" GEOIP_DB="/usr/share/GeoIP/GeoLite2-Country.mmdb" CITY_DB="/usr/share/GeoIP/GeoLite2-City.mmdb" ASN_DB="/usr/share/GeoIP/GeoLite2-ASN.mmdb" @@ -144,8 +144,8 @@ cmd_load() { fi # Restore whitelists - if [ -d "/etc/xdp-blocker/whitelist" ]; then - for wl_file in /etc/xdp-blocker/whitelist/*.txt; do + if [ -d "/etc/xdp-defense/whitelist" ]; then + for wl_file in /etc/xdp-defense/whitelist/*.txt; do [ -f "$wl_file" ] || continue local name name=$(basename "$wl_file" .txt) @@ -480,7 +480,7 @@ cmd_whitelist_add() { bpftool map update id "$map_id" key hex $key_hex value hex 01 00 00 00 00 00 00 00 2>/dev/null # Persist to file for restore on reload - local direct_file="/etc/xdp-blocker/whitelist/direct.txt" + local direct_file="/etc/xdp-defense/whitelist/direct.txt" mkdir -p "$(dirname "$direct_file")" grep -qxF "$name" "$direct_file" 2>/dev/null || echo "$name" >> "$direct_file" @@ -516,7 +516,7 @@ cmd_whitelist_del() { bpftool map delete id "$map_id" key hex $key_hex 2>/dev/null && log_ok "Removed from whitelist: $name" # Remove from persistence file - local direct_file="/etc/xdp-blocker/whitelist/direct.txt" + local direct_file="/etc/xdp-defense/whitelist/direct.txt" if [ -f "$direct_file" ]; then local tmpfile="${direct_file}.tmp.$$" { grep -vxF "$name" "$direct_file" || true; } > "$tmpfile" 2>/dev/null diff --git a/config/config.yaml b/config/config.yaml index caf164c..1e5929e 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -11,7 +11,7 @@ general: blocker: enabled: true - config_dir: /etc/xdp-blocker # existing data path (blocklist, countries, whitelist) + config_dir: /etc/xdp-defense # blocklist, countries, whitelist data rate_limits: default_pps: 2000 # packets per second threshold diff --git a/config/xdp-defense.service b/config/xdp-defense.service index c224d46..6dbabdb 100644 --- a/config/xdp-defense.service +++ b/config/xdp-defense.service @@ -15,7 +15,7 @@ RestartSec=5 # Security hardening ProtectSystem=strict -ReadWritePaths=/var/lib/xdp-defense /etc/xdp-defense /etc/xdp-blocker /sys/fs/bpf /tmp +ReadWritePaths=/var/lib/xdp-defense /etc/xdp-defense /sys/fs/bpf /tmp ProtectHome=true NoNewPrivileges=false CapabilityBoundingSet=CAP_NET_ADMIN CAP_BPF CAP_SYS_ADMIN CAP_PERFMON diff --git a/lib/xdp_common.py b/lib/xdp_common.py index e423f54..618c847 100644 --- a/lib/xdp_common.py +++ b/lib/xdp_common.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ XDP Defense - Common Utilities -Merged from xdp-blocker/xdp_common.py and xdp-ddos/xdp_ddos_common.py +Merged from xdp-defense common utilities Provides: map management, CIDR handling, IP encoding, rate config, block/unblock, stats """ diff --git a/lib/xdp_country.py b/lib/xdp_country.py index bb1ae3a..dff2281 100755 --- a/lib/xdp_country.py +++ b/lib/xdp_country.py @@ -11,7 +11,7 @@ from pathlib import Path from xdp_common import get_map_id, batch_map_operation, classify_cidrs -COUNTRY_DIR = Path("/etc/xdp-blocker/countries") +COUNTRY_DIR = Path("/etc/xdp-defense/countries") IPDENY_V4_URL = "https://www.ipdeny.com/ipblocks/data/countries/{}.zone" IPDENY_V6_URL = "https://www.ipdeny.com/ipblocks/data/ipv6/ipv6-country-blocks/{}.zone" diff --git a/lib/xdp_defense_daemon.py b/lib/xdp_defense_daemon.py index 437e1ad..f2ff24c 100755 --- a/lib/xdp_defense_daemon.py +++ b/lib/xdp_defense_daemon.py @@ -854,6 +854,8 @@ class DDoSDaemon: def _ai_thread(self): """Read traffic features, run AI inference or collect training data.""" prev_features = None + ai_prev_counters = {} + ai_prev_counter_time = 0 self._last_retrain_time = self._get_model_mtime() self._last_log_cleanup = time.time() @@ -931,15 +933,41 @@ class DDoSDaemon: "AI ANOMALY detected: score=%.4f deltas=%s", score, dict(zip(feature_names, deltas[:len(feature_names)])) ) - top_ips = dump_rate_counters('rate_counter_v4', top_n=5) + top_ips = dump_rate_counters('rate_counter_v4', top_n=10) + now_ts = time.time() + ai_elapsed = now_ts - ai_prev_counter_time if ai_prev_counter_time > 0 else interval + ai_prev_counter_time = now_ts + for ip_str, pkts, bts, _ in top_ips: - # Skip whitelisted IPs + prev_pkts = ai_prev_counters.get(ip_str) + ai_prev_counters[ip_str] = pkts + if is_whitelisted(ip_str): log.debug("AI escalation skipped (whitelisted): %s", ip_str) continue + stats = self.ewma_analyzer.get_stats(ip_str) + baseline = max(stats['baseline'], 1) + ewma = stats['ewma'] + + if stats['baseline'] > 0: + if ewma <= baseline * 2.0: + log.debug("AI skip (normal EWMA): %s ewma=%.1f baseline=%.1f", ip_str, ewma, baseline) + continue + else: + pps_limit = self.cfg['rate_limit'].get('pps', 2000) + if prev_pkts is not None: + delta = pkts - prev_pkts if pkts >= prev_pkts else pkts + est_pps = delta / max(ai_elapsed, 1) + if est_pps <= pps_limit: + log.debug("AI skip (new IP, low pps): %s est_pps=%.1f", ip_str, est_pps) + continue + else: + log.debug("AI skip (new IP, first seen): %s", ip_str) + continue + level = self.violation_tracker.record_violation(ip_str) - log.warning("AI escalation: %s -> %s", ip_str, level) + 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) diff --git a/lib/xdp_whitelist.py b/lib/xdp_whitelist.py index 6abeb58..0d9edcc 100755 --- a/lib/xdp_whitelist.py +++ b/lib/xdp_whitelist.py @@ -11,7 +11,7 @@ from pathlib import Path from xdp_common import get_map_id, batch_map_operation, classify_cidrs -WHITELIST_DIR = Path("/etc/xdp-blocker/whitelist") +WHITELIST_DIR = Path("/etc/xdp-defense/whitelist") # Preset URLs for trusted services PRESETS = {