mirror of
https://github.com/icewind1991/warp-real-ip.git
synced 2026-06-03 18:54:06 +02:00
add support for rfc7239 forwarded
This commit is contained in:
parent
411f7a40a7
commit
d573c92d26
4 changed files with 73 additions and 8 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
|
@ -827,6 +827,15 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfc7239"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "087317b3cf7eb481f13bd9025d729324b7cd068d6f470e2d76d049e191f5ba47"
|
||||||
|
dependencies = [
|
||||||
|
"uncased",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
@ -1101,6 +1110,15 @@ version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uncased"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "369fa7fd7969c5373541d3c9a40dc1b76ce676fc87aba30d87c0ad3b97fad179"
|
||||||
|
dependencies = [
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
|
@ -1204,8 +1222,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "warp-real-ip"
|
name = "warp-real-ip"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"rfc7239",
|
||||||
"tokio",
|
"tokio",
|
||||||
"warp",
|
"warp",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "warp-real-ip"
|
name = "warp-real-ip"
|
||||||
description = "Warp filter to get the \"real ip\" of the remote client"
|
description = "Warp filter to get the \"real ip\" of the remote client"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
keywords = ["warp"]
|
keywords = ["warp"]
|
||||||
|
|
@ -12,6 +12,7 @@ documentation = "https://docs.rs/warp-real-ip"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
warp = { version = "0.2" }
|
warp = { version = "0.2" }
|
||||||
|
rfc7239 = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "0.2", features = ["macros"] }
|
tokio = { version = "0.2", features = ["macros"] }
|
||||||
35
src/lib.rs
35
src/lib.rs
|
|
@ -1,3 +1,4 @@
|
||||||
|
use rfc7239::{parse, Forwarded, NodeIdentifier, NodeName};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
|
@ -48,25 +49,47 @@ pub fn real_ip(
|
||||||
/// Creates a `Filter` that extracts the ip addresses from the the "forwarded for" chain
|
/// 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 {
|
pub fn get_forwarded_for() -> impl Filter<Extract = (Vec<IpAddr>,), Error = Infallible> + Clone {
|
||||||
warp::header("x-forwarded-for")
|
warp::header("x-forwarded-for")
|
||||||
.map(|list: IpList| list.0)
|
.map(|list: CommaSeparated<IpAddr>| list.into_inner())
|
||||||
.or(warp::header("x-real-ip").map(|ip| vec![ip]))
|
.or(warp::header("x-real-ip").map(|ip| vec![ip]))
|
||||||
.unify()
|
.unify()
|
||||||
|
.or(warp::header("forwarded").map(|header: String| {
|
||||||
|
parse(&header)
|
||||||
|
.filter_map(|forward| match forward {
|
||||||
|
Ok(Forwarded {
|
||||||
|
forwarded_for:
|
||||||
|
Some(NodeIdentifier {
|
||||||
|
name: NodeName::Ip(ip),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
}) => Some(ip),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}))
|
||||||
|
.unify()
|
||||||
.or(warp::any().map(|| vec![]))
|
.or(warp::any().map(|| vec![]))
|
||||||
.unify()
|
.unify()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Newtype so we can implement FromStr
|
/// Newtype so we can implement FromStr
|
||||||
struct IpList(Vec<IpAddr>);
|
struct CommaSeparated<T>(Vec<T>);
|
||||||
|
|
||||||
impl FromStr for IpList {
|
impl<T> CommaSeparated<T> {
|
||||||
type Err = <IpAddr as FromStr>::Err;
|
pub fn into_inner(self) -> Vec<T> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FromStr> FromStr for CommaSeparated<T> {
|
||||||
|
type Err = T::Err;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let vec = s
|
let vec = s
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(str::trim)
|
.map(str::trim)
|
||||||
.map(IpAddr::from_str)
|
.map(T::from_str)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Ok(IpList(vec))
|
Ok(CommaSeparated(vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,3 +61,25 @@ async fn test_nested_allowed() {
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(res.body(), "11.11.11.11");
|
assert_eq!(res.body(), "11.11.11.11");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_trusted_forwarded() {
|
||||||
|
let remote: IpAddr = [1, 2, 3, 4].into();
|
||||||
|
let res = warp::test::request()
|
||||||
|
.remote_addr((remote, 80).into())
|
||||||
|
.header("forwarded", "for=10.10.10.10")
|
||||||
|
.reply(&serve(vec![remote]))
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.body(), "10.10.10.10");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_trusted_forwarded_no_for() {
|
||||||
|
let remote: IpAddr = [1, 2, 3, 4].into();
|
||||||
|
let res = warp::test::request()
|
||||||
|
.remote_addr((remote, 80).into())
|
||||||
|
.header("forwarded", "by=11.11.11.11")
|
||||||
|
.reply(&serve(vec![remote]))
|
||||||
|
.await;
|
||||||
|
assert_eq!(res.body(), "1.2.3.4");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue