Allow specifying IP networks for permitted proxies in place of IP addresses.

This commit is contained in:
Moriyoshi Koizumi 2021-07-12 09:53:29 +09:00
commit c6af4e7ae9
4 changed files with 45 additions and 5 deletions

10
Cargo.lock generated
View file

@ -378,6 +378,15 @@ dependencies = [
"bytes",
]
[[package]]
name = "ipnetwork"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"
dependencies = [
"serde",
]
[[package]]
name = "itoa"
version = "0.4.7"
@ -1088,6 +1097,7 @@ dependencies = [
name = "warp-real-ip"
version = "0.2.0"
dependencies = [
"ipnetwork",
"rfc7239",
"tokio",
"warp",

View file

@ -13,6 +13,7 @@ documentation = "https://docs.rs/warp-real-ip"
[dependencies]
warp = { version = "0.3" }
rfc7239 = "0.1"
ipnetwork = "~0.18"
[dev-dependencies]
tokio = { version = "1.0", features = ["macros"] }
tokio = { version = "1.0", features = ["macros"] }

View file

@ -1,11 +1,40 @@
use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
use rfc7239::{parse, Forwarded, NodeIdentifier, NodeName};
use std::convert::Infallible;
use std::iter::once;
use std::iter::{once, FromIterator, IntoIterator};
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use warp::filters::addr::remote;
use warp::Filter;
#[derive(Clone)]
pub struct IpNetworks {
networks: Vec<IpNetwork>,
}
impl IpNetworks {
pub fn contains(&self, addr: &IpAddr) -> bool {
self.networks.iter().any(|&network| network.contains(*addr))
}
pub fn from_ipaddr_iter<'a, T: Iterator<Item = &'a IpAddr>>(addrs: T) -> Self {
Self::from_iter(addrs.map(|&addr| -> IpNetwork {
match addr {
IpAddr::V4(addr) => Ipv4Network::from(addr).into(),
IpAddr::V6(addr) => Ipv6Network::from(addr).into(),
}
}))
}
}
impl FromIterator<IpNetwork> for IpNetworks {
fn from_iter<T: IntoIterator<Item = IpNetwork>>(addrs: T) -> Self {
IpNetworks {
networks: Vec::<IpNetwork>::from_iter(addrs),
}
}
}
/// Creates a `Filter` that provides the "real ip" of the connected client.
///
/// This uses the "x-forwarded-for" or "x-real-ip" headers set by reverse proxies.
@ -27,7 +56,7 @@ use warp::Filter;
/// .map(|addr: Option<IpAddr>| format!("Hello {}", addr.unwrap()));
/// ```
pub fn real_ip(
trusted_proxies: Vec<IpAddr>,
trusted_proxies: IpNetworks,
) -> impl Filter<Extract = (Option<IpAddr>,), Error = Infallible> + Clone {
remote().and(get_forwarded_for()).map(
move |addr: Option<SocketAddr>, forwarded_for: Vec<IpAddr>| {

View file

@ -1,10 +1,10 @@
use std::net::IpAddr;
use warp::Filter;
use warp_real_ip::real_ip;
use warp_real_ip::{IpNetworks, real_ip};
fn serve<'a>(trusted: Vec<IpAddr>) -> impl Filter<Extract = (String,)> + 'a {
warp::any()
.and(real_ip(trusted))
.and(real_ip(IpNetworks::from_ipaddr_iter(trusted.iter())))
.map(|addr: Option<IpAddr>| addr.unwrap().to_string())
}