v0.25.1
This commit is contained in:
1 parent
87e571c170
commit
fa7abc9e53
308 files changed
+49746
-50237
No files matched your search
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user