refactor: unify client IP extraction into extract_real_ip
Replace extract_client_ip (manual header parsing without proxy verification) and is_valid_ip with a single extract_real_ip function that uses the same proxy-checking logic as RealIpKeyExtractor. - If peer IP == trusted proxy: use realip_remote_addr() (Forwarded/ X-Forwarded-For) — safe because peer was verified - Otherwise: use peer_addr() directly (local/direct connection) echo_info now extracts the trusted proxy from web::Data<IpAddr> and passes it to extract_real_ip, ensuring consistent IP resolution across rate limiting and address derivation.
This commit is contained in:
@@ -227,8 +227,19 @@ async fn echo_version() -> impl Responder {
|
|||||||
HttpResponse::Ok().body(VERSION)
|
HttpResponse::Ok().body(VERSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_ip(ip: &str) -> bool {
|
fn extract_real_ip(req: &actix_web::HttpRequest, trusted_proxy: IpAddr) -> String {
|
||||||
ip.parse::<std::net::IpAddr>().is_ok()
|
let peer_ip = req.peer_addr().map(|socket| socket.ip());
|
||||||
|
let connection_info = req.connection_info();
|
||||||
|
|
||||||
|
let ip = match peer_ip {
|
||||||
|
Some(peer) if peer == trusted_proxy => {
|
||||||
|
connection_info.realip_remote_addr().unwrap_or("unknown")
|
||||||
|
}
|
||||||
|
_ => connection_info.peer_addr().unwrap_or("unknown"),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("client IP: {}", ip);
|
||||||
|
ip.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -276,37 +287,10 @@ impl KeyExtractor for RealIpKeyExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_client_ip(req: &actix_web::HttpRequest) -> String {
|
|
||||||
if let Some(val) = req.headers().get("X-Real-IP")
|
|
||||||
&& let Ok(s) = val.to_str()
|
|
||||||
{
|
|
||||||
let ip = s.split(',').next().unwrap_or(s).trim();
|
|
||||||
if is_valid_ip(ip) {
|
|
||||||
debug!("client IP from X-Real-IP: {}", ip);
|
|
||||||
return ip.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(val) = req.headers().get("X-Forwarded-For")
|
|
||||||
&& let Ok(s) = val.to_str()
|
|
||||||
{
|
|
||||||
let ip = s.split(',').next().unwrap_or(s).trim();
|
|
||||||
if is_valid_ip(ip) {
|
|
||||||
debug!("client IP from X-Forwarded-For: {}", ip);
|
|
||||||
return ip.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let fallback = req
|
|
||||||
.connection_info()
|
|
||||||
.peer_addr()
|
|
||||||
.unwrap_or("unknown")
|
|
||||||
.to_string();
|
|
||||||
debug!("client IP from peer_addr fallback: {}", fallback);
|
|
||||||
fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn echo_info(
|
async fn echo_info(
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
data: web::Data<AppState>,
|
data: web::Data<AppState>,
|
||||||
|
proxy: web::Data<IpAddr>,
|
||||||
req: actix_web::HttpRequest,
|
req: actix_web::HttpRequest,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let param = path.into_inner();
|
let param = path.into_inner();
|
||||||
@@ -319,7 +303,7 @@ async fn echo_info(
|
|||||||
debug!("network disabled {}", param);
|
debug!("network disabled {}", param);
|
||||||
return HttpResponse::BadRequest().body("error");
|
return HttpResponse::BadRequest().body("error");
|
||||||
}
|
}
|
||||||
let remote_addr = extract_client_ip(&req);
|
let remote_addr = extract_real_ip(&req, **proxy);
|
||||||
let address = match netconfig.xpub {
|
let address = match netconfig.xpub {
|
||||||
false => {
|
false => {
|
||||||
let address = netconfig.address.to_string();
|
let address = netconfig.address.to_string();
|
||||||
|
|||||||
Reference in New Issue
Block a user