mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
Three sources of executor stall under load: * `audit_logger::handle_audit_event` did synchronous `insert_audit_log` inside the broadcast subscriber loop. Every fused-threat emission lands here, so the rusqlite WAL write blocks the worker thread that drains the channel and cascades back-pressure into broadcast Lagged drops. Both AuditEvent and DriftDetectedEvent paths now offload the insert via `spawn_blocking`. * `soar::actions::action_block_ip` made 3-4 synchronous DB calls (`get_setting` x2, `commit_soar_block_to_db`, optional `insert_pending_unblock`) directly inside the SOAR async task body. With r2d2 pool max_size=6 and tokio::spawn-per-event in the SOAR loop, a burst of fused detections starves every other async task. The two setting reads now batch into a single `spawn_blocking` hop, and the commit/pending-unblock writes each run on the blocking pool. * `soar::rate_limit_owner` ran the synchronous `adjust` / `restore_if_expired` bodies (rusqlite + eBPF map writes) directly inside the owner async task. The owner's serialization guarantee is preserved — only one command runs at a time — but each command body now executes on the blocking pool so it can't block the runtime thread that's also draining the command channel. * `suricata_monitor::handle_line` parsed every eve.json line into `serde_json::Value` just to test event_type=="alert", but flow / stats / dns / http / fileinfo lines vastly outnumber alerts on a busy Suricata. Added a cheap substring pre-filter that drops non-alerts before the full parse — the strict event_type check still runs after the parse, so false positives go through without misclassification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
68 lines
2.5 KiB
Rust
68 lines
2.5 KiB
Rust
use macros::traceable;
|
|
|
|
traceable! {
|
|
SoarError {
|
|
#[no_source]
|
|
#[error("Auto-block cap reached (max {max_cap} concurrent blocks)")]
|
|
CapReached { max_cap: u32 } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Invalid TTL: {ttl_secs}s exceeds maximum of {max_secs}s")]
|
|
InvalidTtl { ttl_secs: u64, max_secs: u64 } => tracing::Level::WARN,
|
|
|
|
#[error("SOAR action failed: {action_type} — {err}")]
|
|
ActionFailed { action_type: String } => tracing::Level::ERROR,
|
|
|
|
#[no_source]
|
|
#[error("Unknown SOAR action type: {action_type}")]
|
|
UnknownActionType { action_type: String } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Rate limit config not available for SOAR action")]
|
|
RateLimitUnavailable => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Invalid rate limit factor: {factor} (must be 0.01..=1.0)")]
|
|
InvalidRateLimitFactor { factor: f64 } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Webhook action missing required parameter: {param}")]
|
|
WebhookMissingParam { param: String } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Webhook URL has no host")]
|
|
WebhookUrlNoHost => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Webhook DNS resolution returned no addresses for '{host}'")]
|
|
WebhookDnsEmpty { host: String } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Webhook SSRF blocked: host '{host}' resolves to private IP {ip}")]
|
|
WebhookSsrfBlocked { host: String, ip: String } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Webhook returned non-success HTTP status: {status}")]
|
|
WebhookHttpStatus { status: u16 } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Manual unblock failed: block rule {id} not found")]
|
|
UnblockRuleNotFound { id: i64 } => tracing::Level::WARN,
|
|
|
|
#[error("Failed to clean up ACL rule after unblock: {err}")]
|
|
AclCleanupFailed => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Unknown SOAR condition type: {condition_type}")]
|
|
UnknownConditionType { condition_type: String } => tracing::Level::WARN,
|
|
|
|
#[no_source]
|
|
#[error("Rate-limit owner task is unavailable (channel closed)")]
|
|
RateLimitOwnerUnavailable => tracing::Level::ERROR,
|
|
|
|
#[no_source]
|
|
#[error("Rate-limit owner blocking task panicked or was cancelled: {detail}")]
|
|
RateLimitOwnerJoinFailed { detail: String } => tracing::Level::ERROR,
|
|
}
|
|
}
|