Fetch client ip from X-Forwarded-For, if possible
This commit is contained in:
parent
e21e5fffa5
commit
4007c07dc5
3 changed files with 18 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -224,6 +224,7 @@ dependencies = [
|
|||
"clap",
|
||||
"flume",
|
||||
"hashbrown",
|
||||
"http",
|
||||
"http-body",
|
||||
"itertools 0.14.0",
|
||||
"rand",
|
||||
|
|
|
@ -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"
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue