mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 01:09:23 +00:00
fix(trusted-proxies): validate full Forwarded chain and bare IPv6 (#4461)
This commit is contained in:
@@ -41,6 +41,93 @@ fn test_parse_x_forwarded_for() {
|
||||
assert_eq!(result.len(), 2);
|
||||
}
|
||||
|
||||
// A client-supplied leftmost `Forwarded` element must not be treated as the
|
||||
// real IP: the proxy-appended node further right must win via chain analysis.
|
||||
#[test]
|
||||
fn test_forwarded_resolves_proxy_appended_client_not_spoofed() {
|
||||
let validator = ProxyValidator::new(create_test_config(), None);
|
||||
let peer_addr = Some(SocketAddr::new(IpAddr::from_str("10.0.1.5").unwrap(), 1234));
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("forwarded", "for=1.2.3.4, for=198.51.100.7".parse().unwrap());
|
||||
|
||||
let info = validator.validate_request(peer_addr, &headers).unwrap();
|
||||
assert!(info.is_from_trusted_proxy);
|
||||
assert_eq!(info.real_ip, IpAddr::from_str("198.51.100.7").unwrap());
|
||||
assert_ne!(info.real_ip, IpAddr::from_str("1.2.3.4").unwrap());
|
||||
}
|
||||
|
||||
// A multi-element `Forwarded` header whose rightmost node is trusted validates,
|
||||
// resolving the client to the first untrusted (leftmost) element.
|
||||
#[test]
|
||||
fn test_forwarded_multi_element_trusted_rightmost_validates() {
|
||||
let validator = ProxyValidator::new(create_test_config(), None);
|
||||
let peer_addr = Some(SocketAddr::new(IpAddr::from_str("192.168.1.100").unwrap(), 1234));
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("forwarded", "for=203.0.113.9, for=10.0.0.8".parse().unwrap());
|
||||
|
||||
let info = validator.validate_request(peer_addr, &headers).unwrap();
|
||||
assert!(info.is_from_trusted_proxy);
|
||||
assert_eq!(info.real_ip, IpAddr::from_str("203.0.113.9").unwrap());
|
||||
assert_eq!(info.proxy_hops, 2);
|
||||
}
|
||||
|
||||
// A `proto=https` injected by the client in an earlier element must not set the
|
||||
// forwarded protocol; only the trusted proxy-appended node is authoritative.
|
||||
#[test]
|
||||
fn test_forwarded_client_proto_injection_ignored() {
|
||||
let validator = ProxyValidator::new(create_test_config(), None);
|
||||
let peer_addr = Some(SocketAddr::new(IpAddr::from_str("10.0.1.5").unwrap(), 1234));
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("forwarded", "for=1.2.3.4;proto=https, for=198.51.100.7".parse().unwrap());
|
||||
|
||||
let info = validator.validate_request(peer_addr, &headers).unwrap();
|
||||
assert_eq!(info.real_ip, IpAddr::from_str("198.51.100.7").unwrap());
|
||||
assert_eq!(info.forwarded_proto, None);
|
||||
}
|
||||
|
||||
// Bare IPv6, bracketed IPv6 with a port, and IPv4 with a port must all parse.
|
||||
#[test]
|
||||
fn test_parse_x_forwarded_for_ipv6_and_ports() {
|
||||
assert_eq!(
|
||||
ProxyValidator::parse_x_forwarded_for("2001:db8::1"),
|
||||
vec![IpAddr::from_str("2001:db8::1").unwrap()]
|
||||
);
|
||||
assert_eq!(
|
||||
ProxyValidator::parse_x_forwarded_for("[2001:db8::1]:443"),
|
||||
vec![IpAddr::from_str("2001:db8::1").unwrap()]
|
||||
);
|
||||
assert_eq!(
|
||||
ProxyValidator::parse_x_forwarded_for("203.0.113.1:8080"),
|
||||
vec![IpAddr::from_str("203.0.113.1").unwrap()]
|
||||
);
|
||||
}
|
||||
|
||||
// An IPv6 client behind a trusted IPv6 proxy must resolve to the client, not
|
||||
// collapse to the proxy because of bare-IPv6 truncation.
|
||||
#[test]
|
||||
fn test_ipv6_client_behind_trusted_proxy_resolves_client() {
|
||||
let config = TrustedProxyConfig::new(
|
||||
vec![TrustedProxy::Cidr("fd00::/8".parse().unwrap())],
|
||||
ValidationMode::HopByHop,
|
||||
true,
|
||||
5,
|
||||
true,
|
||||
vec![],
|
||||
);
|
||||
let validator = ProxyValidator::new(config, None);
|
||||
let peer_addr = Some(SocketAddr::new(IpAddr::from_str("fd00::5").unwrap(), 1234));
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("x-forwarded-for", "2001:db8::1234".parse().unwrap());
|
||||
|
||||
let info = validator.validate_request(peer_addr, &headers).unwrap();
|
||||
assert!(info.is_from_trusted_proxy);
|
||||
assert_eq!(info.real_ip, IpAddr::from_str("2001:db8::1234").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_proxy_chain_analyzer_hop_by_hop() {
|
||||
let config = create_test_config();
|
||||
|
||||
Reference in New Issue
Block a user