This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 11:15:58 +02:00
1 parent 87e571c170
commit fa7abc9e53
308 files changed
+49746 -50237

No files matched your search

+166
View File
@@ -0,0 +1,166 @@
mod tests {
use super::*;
use bytes::Bytes;
use http::{Request, Response, Version};
use http_body_util::{BodyExt, Full};
use hyper::service::service_fn;
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
#[test]
fn disabled_backend_certificate_verification_does_not_parse_certificate() {
let provider = rustls::crypto::ring::default_provider();
let verifier = BackendCertificateVerificationDisabled {
supported_schemes: provider
.signature_verification_algorithms
.supported_schemes(),
};
let malformed_or_legacy = CertificateDer::from(vec![0x30, 0x00]);
let server_name = ServerName::try_from("legacy.example").unwrap();
assert!(verifier
.verify_server_cert(
&malformed_or_legacy,
&[],
&server_name,
&[],
UnixTime::since_unix_epoch(Duration::from_secs(0)),
)
.is_ok());
}
#[test]
fn resolved_listener_addresses_and_wildcard_interfaces_are_blocked() {
let policy = AddressPolicy {
allow_private: true,
port: 443,
listeners: vec!["0.0.0.0:443".parse().unwrap()],
local_ips: vec!["192.168.1.5".parse().unwrap()],
interfaces_known: true,
..Default::default()
};
for ip in ["127.0.0.1", "192.168.1.5", "::ffff:127.0.0.1"] {
assert!(policy.check(ip.parse().unwrap()).is_err());
}
assert!(policy.check("93.184.216.34".parse().unwrap()).is_ok());
let answers = vec![
"93.184.216.34:0".parse().unwrap(),
"192.168.1.5:0".parse().unwrap(),
];
assert!(policy.validate_answers(answers.into_iter()).is_err());
}
#[test]
fn explicit_risk_acceptance_allows_local_listener_but_not_private_policy_bypass() {
let mut policy = AddressPolicy {
allow_private: true,
accept_local_listener_risk: true,
port: 9090,
listeners: vec!["127.0.0.1:9090".parse().unwrap()],
local_ips: vec!["127.0.0.1".parse().unwrap()],
interfaces_known: true,
..Default::default()
};
assert!(policy.check("127.0.0.1".parse().unwrap()).is_ok());
policy.allow_private = false;
assert!(policy.check("127.0.0.1".parse().unwrap()).is_err());
}
#[test]
fn wildcard_listener_allows_distinct_remote_private_backend_on_same_port() {
let policy = AddressPolicy {
allow_private: true,
port: 80,
listeners: vec!["0.0.0.0:80".parse().unwrap()],
local_ips: vec!["10.87.2.93".parse().unwrap()],
interfaces_known: true,
..Default::default()
};
assert!(policy.check("10.87.20.2".parse().unwrap()).is_ok());
}
#[tokio::test]
async fn explicit_h2c_backend_uses_http2_prior_knowledge() {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let address = listener.local_addr().unwrap();
let server = tokio::spawn(async move {
let (stream, _) = listener.accept().await.unwrap();
let service = service_fn(|request: Request<hyper::body::Incoming>| async move {
assert_eq!(request.version(), Version::HTTP_2);
Ok::<_, Infallible>(Response::new(Full::new(Bytes::from_static(b"h2-ok"))))
});
let _ = hyper::server::conn::http2::Builder::new(TokioExecutor::new())
.serve_connection(TokioIo::new(stream), service)
.await;
});
let backend: Backend = serde_json::from_value(serde_json::json!({
"id": "h2",
"url": format!("http://{address}"),
"protocol": "http2",
"allow_private": true
}))
.unwrap();
let client = client(&backend, AddressPolicy::new(&backend).unwrap(), false).unwrap();
let request = Request::builder()
.version(Version::HTTP_2)
.uri(format!("http://{address}/probe"))
.body(Body::empty())
.unwrap();
let response = client.request(request).await.unwrap();
assert_eq!(response.version(), Version::HTTP_2);
assert_eq!(
response.into_body().collect().await.unwrap().to_bytes(),
Bytes::from_static(b"h2-ok")
);
server.abort();
}
#[test]
fn mixed_dns_answer_fails_closed() {
let policy = AddressPolicy {
allow_private: false,
allowlist: vec![],
..Default::default()
};
let addresses = vec!["1.1.1.1:0".parse().unwrap(), "127.0.0.1:0".parse().unwrap()];
assert!(policy.validate_answers(addresses.into_iter()).is_err());
}
#[test]
fn allowlist_restricts_even_explicit_private_backends() {
let policy = AddressPolicy {
allow_private: true,
allowlist: vec!["10.2.0.0/16".parse().unwrap()],
..Default::default()
};
assert!(policy.check("10.2.1.1".parse().unwrap()).is_ok());
for ip in [
"10.3.1.1",
"127.0.0.1",
"169.254.169.254",
"100.100.100.200",
] {
assert!(policy.check(ip.parse().unwrap()).is_err(), "{ip}");
}
}
#[test]
fn mapped_addresses_cannot_bypass_ipv4_allowlist() {
let policy = AddressPolicy {
allow_private: true,
allowlist: vec!["127.0.0.1/32".parse().unwrap()],
..Default::default()
};
assert!(policy.check("::ffff:127.0.0.1".parse().unwrap()).is_ok());
assert!(policy
.check("::ffff:169.254.169.254".parse().unwrap())
.is_err());
}
#[test]
fn empty_and_oversized_dns_answers_are_rejected() {
let policy = AddressPolicy {
allow_private: true,
allowlist: vec![],
..Default::default()
};
assert!(policy.validate_answers(std::iter::empty()).is_err());
let addresses = (1..=33).map(|n| format!("10.0.0.{n}:0").parse().unwrap());
assert!(policy.validate_answers(addresses).is_err());
}
}