fix: XDP unsafe loader + Redis sync; enforce 250-line/4-file layout limits

- xdp: CString for if_nametoindex (was UB), real detach via prog fd
  (fabricated borrow_raw(-1) silently never detached), SAFETY comments,
  saturating expiry math; +5 unit tests
- redis: real pubsub reconnect with exponential backoff (was sleep+return);
  KEYS -> SCAN in heartbeat sweep
- ci: cargo test --all-features, repo-gates job — module size gate
  (scripts/check_module_size.sh, ratchet baseline) + default-secrets grep
- refactor src/ to <=250 LOC/file, <=4 .rs/dir without behavior change;
  thin bins (rampart.rs 330 -> 6 LOC), new app/, subnet/, intel/,
  profile/, prefix/, challenge/, filter/, probe/, inventory/, metrics/, node/
- docs: TODO v5.0 (status refresh, new rules, findings backlog),
  README quickstart now matches real binaries
- verify: fmt/clippy -D warnings/test --all-features (164 tests)/clang XDP green
This commit is contained in:
loki5512344 2026-09-15 23:55:17 +02:00
parent d6bcae54c8
commit aa615a1141
Signed by: boba
GPG key ID: 253067914055423B
64 changed files with 2052 additions and 1408 deletions

View file

@ -0,0 +1,121 @@
use serde::Deserialize;
/// Секция `[detect]`: детекторы распределённых атак.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct DetectConfig {
#[serde(default)]
pub prefix: DetectPrefixConfig,
#[serde(default)]
pub autoban: DetectAutobanConfig,
#[serde(default)]
pub alert: DetectAlertConfig,
}
/// Секция `[detect.autoban]`: авто-бан источников по репутации и сигналам
/// детектора атак. Порог сравнивается со скором [`crate::traffic::reputation::IpReputation`],
/// TTL берётся из `ban.ban_duration_secs`.
#[derive(Debug, Clone, Deserialize)]
pub struct DetectAutobanConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_autoban_reputation_threshold")]
pub reputation_threshold: i32,
}
impl Default for DetectAutobanConfig {
fn default() -> Self {
Self {
enabled: false,
reputation_threshold: default_autoban_reputation_threshold(),
}
}
}
fn default_autoban_reputation_threshold() -> i32 {
-50
}
/// Секция `[detect.alert]`: webhook-алерты на переходах состояния атаки
/// («атака началась» / «атака закончилась»).
#[derive(Debug, Clone, Default, Deserialize)]
pub struct DetectAlertConfig {
#[serde(default)]
pub webhook_url: Option<String>,
}
/// Секция `[detect.prefix]`: subnet-level детектор распределённых атак.
#[derive(Debug, Clone, Deserialize)]
pub struct DetectPrefixConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_prefix_syn_threshold")]
pub syn_threshold: u64,
#[serde(default = "default_prefix_window_secs")]
pub window_secs: u64,
#[serde(default = "default_prefix_min_unique_sources")]
pub min_unique_sources: u64,
}
impl Default for DetectPrefixConfig {
fn default() -> Self {
Self {
enabled: false,
syn_threshold: default_prefix_syn_threshold(),
window_secs: default_prefix_window_secs(),
min_unique_sources: default_prefix_min_unique_sources(),
}
}
}
fn default_prefix_syn_threshold() -> u64 {
500
}
fn default_prefix_window_secs() -> u64 {
10
}
fn default_prefix_min_unique_sources() -> u64 {
16
}
/// Секция `[protocol]`: протокольные обработчики (plugin-by-feature).
#[cfg(feature = "protocol-http")]
#[derive(Debug, Clone, Default, Deserialize)]
pub struct ProtocolConfig {
#[serde(default)]
pub http: HttpProtocolConfig,
}
/// Секция `[protocol.http]`: политика HTTP/1.1-обработчика на edge-ноде.
#[cfg(feature = "protocol-http")]
#[derive(Debug, Clone, Deserialize)]
pub struct HttpProtocolConfig {
#[serde(default = "default_http_max_header_bytes")]
pub max_header_bytes: usize,
#[serde(default = "default_http_timeout_secs")]
pub timeout_secs: u64,
#[serde(default)]
pub blocked_paths: Vec<String>,
#[serde(default)]
pub require_user_agent: bool,
}
#[cfg(feature = "protocol-http")]
impl Default for HttpProtocolConfig {
fn default() -> Self {
Self {
max_header_bytes: default_http_max_header_bytes(),
timeout_secs: default_http_timeout_secs(),
blocked_paths: Vec::new(),
require_user_agent: false,
}
}
}
#[cfg(feature = "protocol-http")]
fn default_http_max_header_bytes() -> usize {
8192
}
#[cfg(feature = "protocol-http")]
fn default_http_timeout_secs() -> u64 {
5
}