1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
//! Methods for getting the real IP of a client through a reverse proxy.
//!
//! **Warning**: Make sure your reverse proxy is overwriting the specified header on the incoming requests so clients cant spoof their original Ips.
use std::net::IpAddr;
use crate::{HeaderType, Request};
/// Trait that adds methods for getting the real IP of a client through a reverse proxy.
/// If you are using the "X-Forwarded-For" header you can use `req.real_ip()` but if you are using a different header you will have to use `req.real_ip_header(...)`.
pub trait RealIp {
/// Uses [`RealIp::real_ip_header`] with the ["X-Forwarded-For"](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header.
/// ## Example
/// ```rust
/// use afire::extension::RealIp;
/// # use afire::{Server, Method, Response};
///
/// # fn test(server: &mut Server) {
/// server.route(Method::GET, "/", |req| {
/// let ip = req.real_ip();
/// Response::new().text(format!("Hello, {ip}"))
/// });
/// # }
/// ```
fn real_ip(&self) -> IpAddr {
self.real_ip_header(HeaderType::XForwardedFor)
}
/// Gets the 'real IP' of a client by parsing the value of `header` into an IpAddr.
/// If the connection is not coming from localhost, the header isn't found or the header contains an invalid IP address, the raw socket address will be returned.
///
/// **Warning**: Make sure your reverse proxy is overwriting the specified header on the incoming requests so clients cant spoof their original Ips.
fn real_ip_header(&self, header: impl Into<HeaderType>) -> IpAddr;
}
impl RealIp for Request {
fn real_ip_header(&self, header: impl Into<HeaderType>) -> IpAddr {
let ip = self.address.ip();
// If the connection is not coming from localhost (likely from reverse proxy) return the raw IP
if !ip.is_loopback() {
return ip;
}
// If the 'X-Forwarded-For' Header is present and its value is a valid IP, return it
// Otherwise return the socket address
self.headers
.get(header.into())
.and_then(|x| x.parse().ok())
.unwrap_or(ip)
}
}