#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::string::ToString;
pub use http::header::{HeaderMap, HeaderName, HeaderValue};
#[derive(Clone, Debug)]
pub struct IpWareConfig {
precedence: Vec<HeaderName>,
leftmost: bool,
}
impl Default for IpWareConfig {
fn default() -> Self {
IpWareConfig {
precedence: vec![
HeaderName::from_static("x_forwarded_for"),
HeaderName::from_static("http_x_forwarded_for"), HeaderName::from_static("http_client_ip"),
HeaderName::from_static("http_x_real_ip"),
HeaderName::from_static("http_x_forwarded"), HeaderName::from_static("http_x_cluster_client_ip"),
HeaderName::from_static("http_forwarded_for"), HeaderName::from_static("http_forwarded"), HeaderName::from_static("http_via"), HeaderName::from_static("x-real-ip"), HeaderName::from_static("x-cluster-client-ip"), HeaderName::from_static("x_forwarded"), HeaderName::from_static("forwarded_for"), HeaderName::from_static("cf-connecting-ip"), HeaderName::from_static("true-client-ip"), HeaderName::from_static("fastly-client-ip"), HeaderName::from_static("forwarded"), HeaderName::from_static("client-ip"),
HeaderName::from_static("remote_addr"), ],
leftmost: true,
}
}
}
impl IpWareConfig {
pub fn new<T>(precedence: T, leftmost: bool) -> Self
where
T: Into<Vec<HeaderName>>,
{
IpWareConfig { precedence: precedence.into(), leftmost }
}
pub fn leftmost(mut self, leftmost: bool) -> Self {
self.leftmost = leftmost;
self
}
}
#[derive(Clone, Debug, Default)]
pub struct IpWareProxy {
proxy_count: u16,
proxy_list: Vec<IpAddr>,
}
impl IpWareProxy {
pub fn new<T>(proxy_count: u16, proxy_list: T) -> Self
where
T: Into<Vec<IpAddr>>,
{
IpWareProxy { proxy_count, proxy_list: proxy_list.into() }
}
pub fn is_proxy_count_valid<'a, I>(&self, ip_list: I, strict: bool) -> bool
where
I: IntoIterator<Item = &'a IpAddr>,
{
if self.proxy_count < 1 {
return true;
}
let ip_count = ip_list.into_iter().collect::<Vec<_>>().len();
if ip_count < 1 {
return false;
}
if strict {
return self.proxy_list.len() == ip_count - 1;
}
ip_count - 1 > self.proxy_list.len()
}
pub fn is_proxy_trusted_list_valid<'a, I>(&self, ip_list: I, strict: bool) -> bool
where
I: IntoIterator<Item = &'a IpAddr>,
{
if self.proxy_list.is_empty() {
return true;
}
let ip_list = ip_list.into_iter().collect::<Vec<_>>();
let ip_count = ip_list.len();
let proxy_count = self.proxy_list.len();
if (strict && ip_count - 1 != proxy_count) || (ip_count - 1 < proxy_count) {
return false;
}
ip_list
.into_iter()
.rev()
.take(proxy_count)
.rev()
.zip(self.proxy_list.iter())
.all(|(ip_addr, proxy_addr)| ip_addr == proxy_addr)
}
}
#[derive(Clone, Debug, Default)]
pub struct IpWare {
config: IpWareConfig,
proxy: IpWareProxy,
}
impl IpWare {
pub fn new(config: IpWareConfig, proxy: IpWareProxy) -> Self {
IpWare { config, proxy }
}
fn get_meta_value<'a>(
&self,
headers: &'a HeaderMap,
name: &HeaderName,
) -> Option<&'a HeaderValue> {
match headers.get(name) {
Some(value) => Some(value),
None => headers.get(name.to_string().replace('_', "-")),
}
}
fn get_meta_values<'a>(&self, headers: &'a HeaderMap) -> Vec<&'a str> {
self.config
.precedence
.iter()
.filter_map(|header_name| self.get_meta_value(headers, header_name))
.filter_map(|header_value| header_value.to_str().ok())
.collect()
}
pub fn get_client_ip(&self, headers: &HeaderMap, strict: bool) -> (Option<IpAddr>, bool) {
let mut loopback_list = vec![];
let mut private_list = vec![];
let meta_values = self.get_meta_values(headers);
for &meta_value in meta_values.iter() {
let meta_ips = self.get_ips_from_string(meta_value);
if meta_ips.is_empty() {
continue;
}
let proxy_count_validated = self.proxy.is_proxy_count_valid(&meta_ips, strict);
if !proxy_count_validated {
continue;
}
let proxy_list_validated = self.proxy.is_proxy_trusted_list_valid(&meta_ips, strict);
if !proxy_list_validated {
continue;
}
let (client_ip, trusted_route) =
self.get_best_ip(&meta_ips, proxy_count_validated, proxy_list_validated);
if let Some(client_ip) = client_ip {
if ip_rfc::global(client_ip) {
return (Some(*client_ip), trusted_route);
}
if client_ip.is_loopback() {
loopback_list.push(*client_ip);
} else {
private_list.push(*client_ip);
}
}
}
if !private_list.is_empty() {
return (private_list.first().cloned(), false);
}
if !loopback_list.is_empty() {
return (loopback_list.first().cloned(), false);
}
(None, false)
}
fn get_ips_from_string(&self, ip_str: &str) -> Vec<IpAddr> {
let Ok(mut result): Result<Vec<_>, _> = ip_str
.split(',')
.map(|single_ip| single_ip.trim())
.map(|trimmed_ip| match IpAddr::from_str(trimmed_ip) {
Ok(ip) => Ok(ip),
Err(_) => SocketAddr::from_str(trimmed_ip).map(|socket_addr| socket_addr.ip()),
})
.collect()
else {
return Vec::new();
};
if !self.config.leftmost {
result.reverse();
}
result
}
fn get_best_ip<'a>(
&self,
ip_list: &'a [IpAddr],
proxy_count_validated: bool,
proxy_list_validated: bool,
) -> (Option<&'a IpAddr>, bool) {
if ip_list.is_empty() {
return (None, false);
}
if !self.proxy.proxy_list.is_empty() && proxy_list_validated {
return (ip_list.iter().rev().nth(self.proxy.proxy_list.len()), true);
}
if self.proxy.proxy_count > 0 && proxy_count_validated {
return (
ip_list.iter().rev().nth(self.proxy.proxy_count as usize),
true,
);
}
(ip_list.first(), false)
}
}
#[cfg(test)]
mod tests_ipv4_common {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn empty_header() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let headers = HeaderMap::new();
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn single_header() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_some();
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn multi_header() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "177.139.233.133".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_some();
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn multi_precedence_order() {
let ipware = IpWare::new(
IpWareConfig::new(
vec![
HeaderName::from_static("http_x_forwarded_for"),
HeaderName::from_static("x_forwarded_for"),
],
true,
),
IpWareProxy::default(),
);
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert(
"X_FORWARDED_FOR",
"177.139.233.138, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "177.139.233.133".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_some();
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn multi_precedence_private_first() {
let ipware = IpWare::new(
IpWareConfig::new(
vec![
HeaderName::from_static("http_x_forwarded_for"),
HeaderName::from_static("x_forwarded_for"),
],
true,
),
IpWareProxy::default(),
);
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"10.0.0.0, 10.0.0.1, 10.0.0.2".parse().unwrap(),
);
headers.insert(
"X_FORWARDED_FOR",
"177.139.233.138, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "177.139.233.133".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_some();
assert_that!(ip_addr).contains_value("177.139.233.138".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn multi_precedence_invalid_first() {
let ipware = IpWare::new(
IpWareConfig::new(
vec![
HeaderName::from_static("http_x_forwarded_for"),
HeaderName::from_static("x_forwarded_for"),
],
true,
),
IpWareProxy::default(),
);
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 10.0.0.1, 10.0.0.2".parse().unwrap(),
);
headers.insert(
"X_FORWARDED_FOR",
"177.139.233.138, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "177.139.233.133".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_some();
assert_that!(ip_addr).contains_value("177.139.233.138".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn error_only() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn error_first() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
headers.insert(
"X_FORWARDED_FOR",
"177.139.233.138, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.138".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn singleton() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "177.139.233.139".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn singleton_private_fallback() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "10.0.0.0".parse().unwrap());
headers.insert("HTTP_X_REAL_IP", "177.139.233.139".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn best_matched_ip() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("REMOTE_ADDR", "177.31.233.133".parse().unwrap());
headers.insert("HTTP_X_REAL_IP", "192.168.1.1".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.31.233.133".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn best_matched_ip_public() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("REMOTE_ADDR", "177.31.233.133".parse().unwrap());
headers.insert("HTTP_X_REAL_IP", "177.31.233.122".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.31.233.122".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn best_matched_ip_private() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("REMOTE_ADDR", "127.0.0.1".parse().unwrap());
headers.insert("HTTP_X_REAL_IP", "192.168.1.1".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("192.168.1.1".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn best_matched_ip_private_loopback_precedence() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("REMOTE_ADDR", "192.168.1.1".parse().unwrap());
headers.insert("HTTP_X_REAL_IP", "127.0.0.1".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("192.168.1.1".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn best_matched_ip_private_precedence() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("REMOTE_ADDR", "172.25.0.3".parse().unwrap());
headers.insert("HTTP_X_FORWARDED_FOR", "172.25.0.1".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("172.25.0.1".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn hundred_low_range_public() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_REAL_IP", "100.63.0.9".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("100.63.0.9".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn hundred_block_private() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_REAL_IP", "100.76.0.9".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("100.76.0.9".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn hundred_high_range_public() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_REAL_IP", "100.128.0.9".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("100.128.0.9".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn proxy_order_right_most() {
let ipware = IpWare::new(
IpWareConfig::default().leftmost(false),
IpWareProxy::default(),
);
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("198.84.193.158".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv4_proxy_count {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn singleton_proxy_count() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "177.139.233.139".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn singleton_proxy_count_private() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "10.0.0.0".parse().unwrap());
headers.insert("X_REAL_IP", "177.139.233.139".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn proxy_count_relax() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("198.84.193.157".parse::<IpAddr>().unwrap());
assert!(trusted_route);
}
#[test]
fn proxy_count_strict() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.138, 177.139.233.139, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, true);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv4_proxy_list {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn proxy_list_strict_success() {
let proxies = vec![
"198.84.193.157".parse::<IpAddr>().unwrap(),
"198.84.193.158".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, true);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(trusted_route);
}
#[test]
fn proxy_list_strict_failure() {
let proxies = vec![
"198.84.193.157".parse::<IpAddr>().unwrap(),
"198.84.193.158".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.138, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, true);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn proxy_list_success() {
let proxies = vec![
"198.84.193.157".parse::<IpAddr>().unwrap(),
"198.84.193.158".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.138, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(trusted_route);
}
}
#[cfg(test)]
mod tests_ipv4_proxy_count_proxy_list {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn proxy_list_relax() {
let proxies = vec![
"198.84.193.157".parse::<IpAddr>().unwrap(),
"198.84.193.158".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(2, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.138, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(trusted_route);
}
#[test]
fn proxy_list_strict() {
let proxies = vec![
"198.84.193.157".parse::<IpAddr>().unwrap(),
"198.84.193.158".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(2, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.138, 177.139.233.139, 198.84.193.157, 198.84.193.158"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, true);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv4_port {
use spectral::assert_that;
use spectral::option::ContainingOptionAssertions;
use super::*;
#[test]
fn ipv4_public_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"177.139.233.139:80".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("177.139.233.139".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn ipv4_private_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"10.0.0.1:443, 10.0.0.1, 10.0.0.2".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("10.0.0.1".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
#[test]
fn ipv4_loopback_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "127.0.0.1:80".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value("127.0.0.1".parse::<IpAddr>().unwrap());
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv6_common {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn single_header() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn multi_header() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "74dc:2bc".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn multi_precedence_order() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("X_FORWARDED_FOR", "74dc:2be, 74dc:2bf".parse().unwrap());
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
headers.insert("REMOTE_ADDR", "74dc:2bc".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn multi_precedence_private_first() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
headers.insert("HTTP_X_FORWARDED_FOR", "2001:db8:, ::1".parse().unwrap());
headers.insert("REMOTE_ADDR", "74dc:2bc".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn multi_precedence_invalid_first() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 2001:db8:, ::1".parse().unwrap(),
);
headers.insert("REMOTE_ADDR", "74dc:2bc".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn error_only() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"X_FORWARDED_FOR",
"unknown, 3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn first_error_bailout() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn error_beast_match() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"unknown, 3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
headers.insert(
"X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn singleton() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
#[test]
fn singleton_private_fallback() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "::1".parse().unwrap());
headers.insert(
"HTTP_X_REAL_IP",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv6_proxy_count {
use spectral::assert_that;
use spectral::option::OptionAssertions;
use super::*;
#[test]
fn singleton_proxy_count() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf".parse().unwrap(),
);
headers.insert("HTTP_X_REAL_IP", "2606:4700:4700::1111".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
#[test]
fn singleton_proxy_count_private() {
let proxies = vec![];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(1, proxies));
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "::1".parse().unwrap());
headers.insert(
"HTTP_X_REAL_IP",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv6_proxy_list {
use spectral::assert_that;
use spectral::option::{ContainingOptionAssertions, OptionAssertions};
use super::*;
#[test]
fn proxy_trusted_proxy_strict() {
let proxies = vec![
"2606:4700:4700::1111".parse::<IpAddr>().unwrap(),
"2001:4860:4860::8888".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, true);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(trusted_route);
}
#[test]
fn proxy_trusted_proxy_not_strict() {
let proxies = vec![
"2606:4700:4700::1111".parse::<IpAddr>().unwrap(),
"2001:4860:4860::8888".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(trusted_route);
}
#[test]
fn proxy_trusted_proxy_not_strict_long() {
let proxies = vec![
"2606:4700:4700::1111".parse::<IpAddr>().unwrap(),
"2001:4860:4860::8888".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"2001:4860:4860::7777,3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(
"3ffe:1900:4545:3:200:f8ff:fe21:67cf"
.parse::<IpAddr>()
.unwrap(),
);
assert!(trusted_route);
}
#[test]
fn proxy_trusted_proxy_error() {
let proxies = vec![
"2606:4700:4700::1111".parse::<IpAddr>().unwrap(),
"2001:4860:4860::8888".parse::<IpAddr>().unwrap(),
];
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::new(0, proxies));
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"3ffe:1900:4545:3:200:f8ff:fe21:67cf, 2606:4700:4700::1111, 74dc::2bb"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).is_none();
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv6_encapsulation {
use std::net::Ipv4Addr;
use spectral::assert_that;
use spectral::option::ContainingOptionAssertions;
use super::*;
#[test]
fn ipv6_encapsulation_of_ipv4_private() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "::ffff:127.0.0.1".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr)
.contains_value(IpAddr::V6(Ipv4Addr::new(127, 0, 0, 1).to_ipv6_mapped()));
assert!(!trusted_route);
}
#[test]
fn ipv6_encapsulation_of_ipv4_public() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"::ffff:177.139.233.139".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(IpAddr::V6(
Ipv4Addr::new(177, 139, 233, 139).to_ipv6_mapped(),
));
assert!(!trusted_route);
}
}
#[cfg(test)]
mod tests_ipv6_with_port {
use std::net::{Ipv4Addr, Ipv6Addr};
use spectral::assert_that;
use spectral::option::ContainingOptionAssertions;
use super::*;
#[test]
fn encapsulation_of_ipv4_public_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"[::ffff:177.139.233.139]:80".parse().unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(IpAddr::V6(
Ipv4Addr::new(177, 139, 233, 139).to_ipv6_mapped(),
));
assert!(!trusted_route);
}
#[test]
fn ipv6_public_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert(
"HTTP_X_FORWARDED_FOR",
"[3ffe:1900:4545:3:200:f8ff:fe21:67cf]:443, 2606:4700:4700::1111, 2001:4860:4860::8888"
.parse()
.unwrap(),
);
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(IpAddr::V6(Ipv6Addr::new(
0x3ffe, 0x1900, 0x4545, 0x3, 0x200, 0xf8ff, 0xfe21, 0x67cf,
)));
assert!(!trusted_route);
}
#[test]
fn ipv6_loopback_with_port() {
let ipware = IpWare::new(IpWareConfig::default(), IpWareProxy::default());
let mut headers = HeaderMap::new();
headers.insert("HTTP_X_FORWARDED_FOR", "[::1]:80".parse().unwrap());
let (ip_addr, trusted_route) = ipware.get_client_ip(&headers, false);
assert_that!(ip_addr).contains_value(IpAddr::V6("::1".parse::<Ipv6Addr>().unwrap()));
assert!(!trusted_route);
}
}