Feature - Detect real IP of client using new config option (#2100)
This commit is contained in:
parent
f5f10d508f
commit
de016af929
5 changed files with 67 additions and 5 deletions
|
@ -1,3 +1,4 @@
|
|||
use crate::net::client_ip::ClientIp;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::{net::SocketAddr, path::PathBuf};
|
||||
|
||||
|
@ -8,6 +9,7 @@ pub struct Config {
|
|||
pub strict: bool,
|
||||
pub bind: SocketAddr,
|
||||
pub path: String,
|
||||
pub client_ip: ClientIp,
|
||||
pub user: String,
|
||||
pub pass: Option<String>,
|
||||
pub crt: Option<PathBuf>,
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::dbs;
|
|||
use crate::env;
|
||||
use crate::err::Error;
|
||||
use crate::iam;
|
||||
use crate::net;
|
||||
use crate::net::{self, client_ip::ClientIp};
|
||||
use clap::Args;
|
||||
use ipnet::IpNet;
|
||||
use std::net::SocketAddr;
|
||||
|
@ -31,6 +31,10 @@ pub struct StartCommandArguments {
|
|||
#[arg(env = "SURREAL_ADDR", long = "addr")]
|
||||
#[arg(default_value = "127.0.0.1/32")]
|
||||
allowed_networks: Vec<IpNet>,
|
||||
#[arg(help = "The method of detecting the client's IP address")]
|
||||
#[arg(env = "SURREAL_CLIENT_IP", long)]
|
||||
#[arg(default_value = "socket", value_enum)]
|
||||
client_ip: ClientIp,
|
||||
#[arg(help = "The hostname or ip address to listen for connections on")]
|
||||
#[arg(env = "SURREAL_BIND", short = 'b', long = "bind")]
|
||||
#[arg(default_value = "0.0.0.0:8000")]
|
||||
|
@ -88,6 +92,7 @@ pub async fn init(
|
|||
path,
|
||||
username: user,
|
||||
password: pass,
|
||||
client_ip,
|
||||
listen_addresses,
|
||||
web,
|
||||
strict,
|
||||
|
@ -108,6 +113,7 @@ pub async fn init(
|
|||
let _ = config::CF.set(Config {
|
||||
strict,
|
||||
bind: listen_addresses.first().cloned().unwrap(),
|
||||
client_ip,
|
||||
path,
|
||||
user,
|
||||
pass,
|
||||
|
|
55
src/net/client_ip.rs
Normal file
55
src/net/client_ip.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::cli::CF;
|
||||
use clap::ValueEnum;
|
||||
use std::net::IpAddr;
|
||||
use std::net::SocketAddr;
|
||||
use warp::Filter;
|
||||
|
||||
// TODO: Support Forwarded, X-Forwarded-For headers.
|
||||
#[derive(ValueEnum, Clone, Copy, Debug)]
|
||||
pub enum ClientIp {
|
||||
/// Don't use client IP
|
||||
None,
|
||||
/// Raw socket IP
|
||||
Socket,
|
||||
/// Cloudflare connecting IP
|
||||
#[clap(name = "CF-Connecting-IP")]
|
||||
CfConectingIp,
|
||||
/// Fly.io client IP
|
||||
#[clap(name = "Fly-Client-IP")]
|
||||
FlyClientIp,
|
||||
/// Akamai, Cloudflare true client IP
|
||||
#[clap(name = "True-Client-IP")]
|
||||
TrueClientIP,
|
||||
/// Nginx real IP
|
||||
#[clap(name = "X-Real-IP")]
|
||||
XRealIp,
|
||||
}
|
||||
|
||||
/// Creates an string represenation of the client's IP address
|
||||
pub fn build() -> impl Filter<Extract = (Option<String>,), Error = warp::Rejection> + Clone {
|
||||
// Get configured client IP source
|
||||
let client_ip = CF.get().unwrap().client_ip;
|
||||
// Enable on any path
|
||||
let conf = warp::any();
|
||||
// Add raw remote IP address
|
||||
let conf =
|
||||
conf.and(warp::filters::addr::remote().and_then(move |s: Option<SocketAddr>| async move {
|
||||
match client_ip {
|
||||
ClientIp::None => Ok(None),
|
||||
ClientIp::Socket => Ok(s.map(|s| s.ip())),
|
||||
// Move on to parsing selected IP header.
|
||||
_ => Err(warp::reject::reject()),
|
||||
}
|
||||
}));
|
||||
// Add selected IP header
|
||||
let conf = conf.or(warp::header::optional::<IpAddr>(match client_ip {
|
||||
ClientIp::CfConectingIp => "Cf-Connecting-IP",
|
||||
ClientIp::FlyClientIp => "Fly-Client-IP",
|
||||
ClientIp::TrueClientIP => "True-Client-IP",
|
||||
ClientIp::XRealIp => "X-Real-IP",
|
||||
// none and socket are already handled so this will never be used
|
||||
_ => "unreachable",
|
||||
}));
|
||||
// Join the two filters
|
||||
conf.unify().map(|ip: Option<IpAddr>| ip.map(|ip| ip.to_string()))
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod client_ip;
|
||||
mod export;
|
||||
mod fail;
|
||||
mod head;
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::err::Error;
|
|||
use crate::iam::verify::{basic, token};
|
||||
use crate::iam::BASIC;
|
||||
use crate::iam::TOKEN;
|
||||
use std::net::SocketAddr;
|
||||
use crate::net::client_ip;
|
||||
use surrealdb::dbs::Session;
|
||||
use warp::Filter;
|
||||
|
||||
|
@ -10,9 +10,7 @@ pub fn build() -> impl Filter<Extract = (Session,), Error = warp::Rejection> + C
|
|||
// Enable on any path
|
||||
let conf = warp::any();
|
||||
// Add remote ip address
|
||||
let conf = conf.and(warp::filters::addr::remote());
|
||||
// Add remote ip address
|
||||
let conf = conf.map(|addr: Option<SocketAddr>| addr.map(|v| v.to_string()));
|
||||
let conf = conf.and(client_ip::build());
|
||||
// Add authorization header
|
||||
let conf = conf.and(warp::header::optional::<String>("authorization"));
|
||||
// Add http origin header
|
||||
|
|
Loading…
Reference in a new issue