1 Commits

Author SHA1 Message Date
7999902cc0 fix: extract client IP correctly behind reverse proxy
Add X-Forwarded-For as fallback header when X-Real-IP is missing.
Validate IP format before storing. Log which source was used.

release: bal-server-0.3.2
2026-07-20 13:34:03 -04:00
2 changed files with 34 additions and 13 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "bal_server" name = "bal_server"
version = "0.3.1" version = "0.3.2"
edition = "2024" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -217,6 +217,38 @@ async fn echo_version() -> impl Responder {
HttpResponse::Ok().body(VERSION) HttpResponse::Ok().body(VERSION)
} }
fn is_valid_ip(ip: &str) -> bool {
ip.parse::<std::net::IpAddr>().is_ok()
}
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>,
@@ -232,18 +264,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 = req let remote_addr = extract_client_ip(&req);
.headers()
.get("X-Real-IP")
.and_then(|value| value.to_str().ok())
.and_then(|xff| xff.split(',').next())
.map(|ip| ip.trim().to_string())
.unwrap_or_else(|| {
req.connection_info()
.peer_addr()
.unwrap_or("unknown")
.to_string()
});
let address = match netconfig.xpub { let address = match netconfig.xpub {
false => { false => {
let address = netconfig.address.to_string(); let address = netconfig.address.to_string();