mirror of
https://github.com/icewind1991/warp-real-ip.git
synced 2026-06-03 18:54:06 +02:00
support nested proxies
This commit is contained in:
parent
14e7393db6
commit
a04638e1f6
2 changed files with 51 additions and 14 deletions
43
src/lib.rs
43
src/lib.rs
|
|
@ -1,5 +1,7 @@
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
use std::iter::once;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use std::str::FromStr;
|
||||||
use warp::filters::addr::remote;
|
use warp::filters::addr::remote;
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
|
|
@ -23,23 +25,36 @@ use warp::Filter;
|
||||||
pub fn real_ip(
|
pub fn real_ip(
|
||||||
trusted_proxies: Vec<IpAddr>,
|
trusted_proxies: Vec<IpAddr>,
|
||||||
) -> impl Filter<Extract = (Option<IpAddr>,), Error = Infallible> + Clone {
|
) -> impl Filter<Extract = (Option<IpAddr>,), Error = Infallible> + Clone {
|
||||||
let forwarded_for = warp::header::<IpAddr>("x-forwarded-for")
|
remote().and(get_forwarded_for()).map(
|
||||||
.or(warp::header("x-real-ip"))
|
move |addr: Option<SocketAddr>, forwarded_for: Vec<IpAddr>| {
|
||||||
.unify()
|
|
||||||
.map(Some)
|
|
||||||
.or(warp::any().map(|| None))
|
|
||||||
.unify();
|
|
||||||
|
|
||||||
remote().and(forwarded_for).map(
|
|
||||||
move |addr: Option<SocketAddr>, forwarded_for: Option<IpAddr>| {
|
|
||||||
addr.map(|addr| {
|
addr.map(|addr| {
|
||||||
let ip = addr.ip();
|
let hops = forwarded_for.iter().copied().chain(once(addr.ip()));
|
||||||
if trusted_proxies.contains(&ip) {
|
for hop in hops.rev() {
|
||||||
forwarded_for.unwrap_or(ip)
|
if !trusted_proxies.contains(&hop) {
|
||||||
} else {
|
return hop;
|
||||||
ip
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all hops were trusted, return the last one
|
||||||
|
forwarded_for.first().copied().unwrap_or(addr.ip())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a `Filter` that extracts the ip addresses from the the "forwarded for" chain
|
||||||
|
pub fn get_forwarded_for() -> impl Filter<Extract = (Vec<IpAddr>,), Error = Infallible> + Clone {
|
||||||
|
warp::header::<String>("x-forwarded-for")
|
||||||
|
.map(|forwarded: String| {
|
||||||
|
forwarded
|
||||||
|
.split(',')
|
||||||
|
.map(str::trim)
|
||||||
|
.map(IpAddr::from_str)
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.collect::<Vec<IpAddr>>()
|
||||||
|
})
|
||||||
|
.or(warp::header("x-real-ip").map(|ip| vec![ip]))
|
||||||
|
.unify()
|
||||||
|
.or(warp::any().map(|| vec![]))
|
||||||
|
.unify()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,25 @@ async fn test_trusted() {
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(res.body(), "10.10.10.10");
|
assert_eq!(res.body(), "10.10.10.10");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_nested_denied() {
|
||||||
|
let remote: IpAddr = [1, 2, 3, 4].into();
|
||||||
|
let res = warp::test::request()
|
||||||
|
.remote_addr((remote, 80).into())
|
||||||
|
.header("x-forwarded-for", "10.10.10.10, 11.11.11.11")
|
||||||
|
.reply(&serve(vec![remote]))
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.body(), "11.11.11.11");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_nested_allowed() {
|
||||||
|
let remote: IpAddr = [1, 2, 3, 4].into();
|
||||||
|
let res = warp::test::request()
|
||||||
|
.remote_addr((remote, 80).into())
|
||||||
|
.header("x-forwarded-for", "10.10.10.10, 11.11.11.11")
|
||||||
|
.reply(&serve(vec![remote, [10, 10, 10, 10].into()]))
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.body(), "11.11.11.11");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue