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 <sienna@sunbeam.pt>
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
37
src/proxy.rs
37
src/proxy.rs
@@ -43,6 +43,8 @@ pub struct SunbeamProxy {
|
||||
pub compiled_rewrites: Vec<(String, Vec<CompiledRewrite>)>,
|
||||
/// 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<crate::rate_limit::cidr::CidrBlock>,
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user