From 2660ee974c939b62b0d09c125f41c63dfbabc979 Mon Sep 17 00:00:00 2001 From: Sienna Meridian Satterwhite Date: Tue, 10 Mar 2026 23:38:20 +0000 Subject: [PATCH] fix(proxy): skip detection pipeline for bypass CIDR IPs Trusted IPs (localhost, pod network) now skip the entire DDoS/scanner/ rate-limit pipeline via early return. Fixes buildkitd pushes to Gitea being blocked by the scanner when using host networking. Signed-off-by: Sienna Meridian Satterwhite --- src/main.rs | 3 +++ src/proxy.rs | 37 +++++++++++++++++++++++++++++++++++++ tests/e2e.rs | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4b5497f..868c271 100644 --- a/src/main.rs +++ b/src/main.rs @@ -365,6 +365,9 @@ fn run_serve(upgrade: bool) -> Result<()> { rate_limiter, compiled_rewrites, http_client, + pipeline_bypass_cidrs: crate::rate_limit::cidr::parse_cidrs( + &cfg.rate_limit.as_ref().map(|rl| rl.bypass_cidrs.clone()).unwrap_or_default(), + ), }; let mut svc = http_proxy_service(&server.configuration, proxy); diff --git a/src/proxy.rs b/src/proxy.rs index 45360bb..3ce401f 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -43,6 +43,8 @@ pub struct SunbeamProxy { pub compiled_rewrites: Vec<(String, Vec)>, /// Shared reqwest client for auth subrequests. pub http_client: reqwest::Client, + /// Parsed bypass CIDRs — IPs in these ranges skip the detection pipeline. + pub pipeline_bypass_cidrs: Vec, } pub struct RequestCtx { @@ -278,6 +280,14 @@ impl ProxyHttp for SunbeamProxy { // - "scanner" log = traffic that passed DDoS (rate-limit training data) // - "rate_limit" log = traffic that passed scanner (validation data) + // Skip the detection pipeline for trusted IPs (localhost, pod network). + if extract_client_ip(session) + .map(|ip| crate::rate_limit::cidr::is_bypassed(ip, &self.pipeline_bypass_cidrs)) + .unwrap_or(false) + { + return Ok(false); + } + // DDoS detection: check the client IP against the KNN model. if let Some(detector) = &self.ddos_detector { if let Some(ip) = extract_client_ip(session) { @@ -1219,6 +1229,33 @@ mod tests { assert!(uuid::Uuid::parse_str(&id).is_ok()); } + #[test] + fn test_pipeline_bypass_cidrs_parsed() { + use crate::rate_limit::cidr::{parse_cidrs, is_bypassed}; + let cidrs = parse_cidrs(&[ + "10.42.0.0/16".into(), + "127.0.0.0/8".into(), + "::1/128".into(), + ]); + // Pod network + assert!(is_bypassed("10.42.1.5".parse().unwrap(), &cidrs)); + // Localhost IPv4 + assert!(is_bypassed("127.0.0.1".parse().unwrap(), &cidrs)); + // Localhost IPv6 + assert!(is_bypassed("::1".parse().unwrap(), &cidrs)); + // External IP should not be bypassed + assert!(!is_bypassed("8.8.8.8".parse().unwrap(), &cidrs)); + assert!(!is_bypassed("192.168.1.1".parse().unwrap(), &cidrs)); + } + + #[test] + fn test_pipeline_bypass_empty_cidrs_blocks_nothing() { + use crate::rate_limit::cidr::{parse_cidrs, is_bypassed}; + let cidrs = parse_cidrs(&[]); + assert!(!is_bypassed("127.0.0.1".parse().unwrap(), &cidrs)); + assert!(!is_bypassed("10.42.0.1".parse().unwrap(), &cidrs)); + } + #[test] fn test_compile_rewrites_valid() { let routes = vec![RouteConfig { diff --git a/tests/e2e.rs b/tests/e2e.rs index 0edb517..ee7be37 100644 --- a/tests/e2e.rs +++ b/tests/e2e.rs @@ -108,7 +108,7 @@ fn start_proxy_once(backend_port: u16) { }]; let acme_routes: AcmeRoutes = Arc::new(RwLock::new(HashMap::new())); let compiled_rewrites = SunbeamProxy::compile_rewrites(&routes); - let proxy = SunbeamProxy { routes, acme_routes, ddos_detector: None, scanner_detector: None, bot_allowlist: None, rate_limiter: None, compiled_rewrites, http_client: reqwest::Client::new() }; + let proxy = SunbeamProxy { routes, acme_routes, ddos_detector: None, scanner_detector: None, bot_allowlist: None, rate_limiter: None, compiled_rewrites, http_client: reqwest::Client::new(), pipeline_bypass_cidrs: vec![] }; let opt = Opt { upgrade: false,