Feature - Detect real IP of client using new config option ()

This commit is contained in:
Finn Bear 2023-06-05 23:31:45 -07:00 committed by GitHub
parent f5f10d508f
commit de016af929
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 5 deletions

View file

@ -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>,

View file

@ -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
View 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()))
}

View file

@ -1,3 +1,4 @@
pub mod client_ip;
mod export;
mod fail;
mod head;

View file

@ -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