use std::net::{IpAddr, SocketAddr}; use axum::http::HeaderMap; use ipnet::IpNet; pub fn resolve_client_ip( peer: Option, headers: &HeaderMap, trusted_proxies: &[IpNet], ) -> Option { match peer { Some(addr) if in_nets(addr.ip(), trusted_proxies) => forwarded_ip(headers), Some(addr) => Some(addr.ip()), None => None, } } pub fn in_nets(ip: IpAddr, nets: &[IpNet]) -> bool { nets.iter().any(|net| net.contains(&ip)) } fn forwarded_ip(headers: &HeaderMap) -> Option { if let Some(value) = headers .get("x-forwarded-for") .and_then(|value| value.to_str().ok()) && let Some(first) = value .split(',') .map(str::trim) .find(|item| !item.is_empty()) && let Ok(ip) = first.parse::() { return Some(ip); } if let Some(value) = headers .get("x-real-ip") .and_then(|value| value.to_str().ok()) && let Ok(ip) = value.trim().parse::() { return Some(ip); } None }