Fetch client ip from X-Forwarded-For, if possible

This commit is contained in:
Joshua Barretto 2025-04-29 20:57:25 +01:00
parent e21e5fffa5
commit 4007c07dc5
3 changed files with 18 additions and 7 deletions

1
Cargo.lock generated
View file

@ -224,6 +224,7 @@ dependencies = [
"clap",
"flume",
"hashbrown",
"http",
"http-body",
"itertools 0.14.0",
"rand",

View file

@ -11,6 +11,7 @@ chrono = "0.4.40"
clap = { version = "4.5.37", features = ["derive"] }
flume = "0.11.1"
hashbrown = "0.15.2"
http = "1.3.1"
http-body = "1.0.1"
itertools = "0.14.0"
rand = "0.9.1"

View file

@ -10,6 +10,7 @@ use axum::{
use axum_server::{bind_rustls, tls_rustls::RustlsConfig};
use clap::Parser;
use hashbrown::HashMap;
use http::HeaderMap;
use http_body::Frame;
use itertools::Itertools;
use rand::{prelude::*, Rng as _};
@ -17,7 +18,7 @@ use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use std::{
borrow::Cow,
convert::Infallible,
net::SocketAddr,
net::{IpAddr, SocketAddr},
path::PathBuf,
pin::Pin,
sync::{
@ -93,7 +94,7 @@ impl IntoResponse for SlowBody {
}
struct RequestStats {
sock: SocketAddr,
ip: IpAddr,
}
#[tokio::main]
@ -124,11 +125,19 @@ async fn main() {
Router::new().route(
"/{id}",
get(
|Path(id): Path<String>, ConnectInfo(sock): ConnectInfo<SocketAddr>| async move {
|Path(id): Path<String>,
ConnectInfo(sock): ConnectInfo<SocketAddr>,
headers: HeaderMap| async move {
// Create a RNG for this path (deterministic, to simulate static pages)
let mut rng = create_rng(id.bytes());
stats_tx.send(RequestStats { sock }).unwrap();
let ip = headers
.get("X-Forwarded-For")
.and_then(|h| h.to_str().ok())
.and_then(|h| h.split(',').next())
.and_then(|s| s.trim().parse().ok())
.unwrap_or_else(|| sock.ip());
stats_tx.send(RequestStats { ip }).unwrap();
// Count the request. Also doubles as the non-deterministic seed
let count = counter.fetch_add(1, Ordering::Relaxed);
@ -197,7 +206,7 @@ async fn main() {
interval.tick().await;
while let Ok(stats) = stats_rx.try_recv() {
*worst_offenders.entry(stats.sock.ip()).or_default() += 1;
*worst_offenders.entry(stats.ip).or_default() += 1;
}
let count = counter.load(Ordering::Relaxed);
@ -210,8 +219,8 @@ async fn main() {
let stats = worst_offenders
.iter()
.enumerate()
.map(|(i, (sock, n))| format!("#{:>4} | {:>4} | {}", i + 1, n, sock))
.join("\n");
.map(|(i, (ip, n))| format!("#{:>4} | {:>4} | {}\n", i + 1, n, ip))
.collect::<String>();
let _ = std::fs::write(STATS_FILE, &stats);
}
}