mirror of https://github.com/telemt/telemt.git
feat: add mask_proxy_protocol option for forwarding client IP to mask_host
Adds mask_proxy_protocol config option (0=off, 1=v1, 2=v2) that sends a PROXY protocol header when connecting to mask_host, allowing the backend to see the real client IP address.
This commit is contained in:
parent
e8787c39d1
commit
2ad79627bf
|
|
@ -135,6 +135,7 @@ mask = true
|
|||
# mask_host = "www.google.com" # example, defaults to tls_domain when both mask_host/mask_unix_sock are unset
|
||||
# mask_unix_sock = "/var/run/nginx.sock" # example, mutually exclusive with mask_host
|
||||
mask_port = 443
|
||||
# mask_proxy_protocol = 0 # Send PROXY protocol header to mask_host: 0 = off, 1 = v1 (text), 2 = v2 (binary)
|
||||
fake_cert_len = 2048 # if tls_emulation=false and default value is used, loader may randomize this value at runtime
|
||||
tls_emulation = true
|
||||
tls_front_dir = "tlsfront"
|
||||
|
|
|
|||
|
|
@ -611,6 +611,12 @@ pub struct AntiCensorshipConfig {
|
|||
/// Enforce ALPN echo of client preference.
|
||||
#[serde(default = "default_alpn_enforce")]
|
||||
pub alpn_enforce: bool,
|
||||
|
||||
/// Send PROXY protocol header when connecting to mask_host.
|
||||
/// 0 = disabled, 1 = v1 (text), 2 = v2 (binary).
|
||||
/// Allows the backend to see the real client IP.
|
||||
#[serde(default)]
|
||||
pub mask_proxy_protocol: u8,
|
||||
}
|
||||
|
||||
impl Default for AntiCensorshipConfig {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ where
|
|||
reader,
|
||||
writer,
|
||||
&first_bytes,
|
||||
real_peer.ip(),
|
||||
real_peer,
|
||||
&config,
|
||||
&beobachten,
|
||||
)
|
||||
|
|
@ -168,7 +168,7 @@ where
|
|||
reader,
|
||||
writer,
|
||||
&handshake,
|
||||
real_peer.ip(),
|
||||
real_peer,
|
||||
&config,
|
||||
&beobachten,
|
||||
)
|
||||
|
|
@ -212,7 +212,7 @@ where
|
|||
reader,
|
||||
writer,
|
||||
&first_bytes,
|
||||
real_peer.ip(),
|
||||
real_peer,
|
||||
&config,
|
||||
&beobachten,
|
||||
)
|
||||
|
|
@ -237,7 +237,7 @@ where
|
|||
reader,
|
||||
writer,
|
||||
&handshake,
|
||||
real_peer.ip(),
|
||||
real_peer,
|
||||
&config,
|
||||
&beobachten,
|
||||
)
|
||||
|
|
@ -462,7 +462,7 @@ impl RunningClientHandler {
|
|||
reader,
|
||||
writer,
|
||||
&first_bytes,
|
||||
peer.ip(),
|
||||
peer,
|
||||
&self.config,
|
||||
&self.beobachten,
|
||||
)
|
||||
|
|
@ -501,7 +501,7 @@ impl RunningClientHandler {
|
|||
reader,
|
||||
writer,
|
||||
&handshake,
|
||||
peer.ip(),
|
||||
peer,
|
||||
&config,
|
||||
&self.beobachten,
|
||||
)
|
||||
|
|
@ -570,7 +570,7 @@ impl RunningClientHandler {
|
|||
reader,
|
||||
writer,
|
||||
&first_bytes,
|
||||
peer.ip(),
|
||||
peer,
|
||||
&self.config,
|
||||
&self.beobachten,
|
||||
)
|
||||
|
|
@ -608,7 +608,7 @@ impl RunningClientHandler {
|
|||
reader,
|
||||
writer,
|
||||
&handshake,
|
||||
peer.ip(),
|
||||
peer,
|
||||
&config,
|
||||
&self.beobachten,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Masking - forward unrecognized traffic to mask host
|
||||
|
||||
use std::str;
|
||||
use std::net::IpAddr;
|
||||
use std::net::SocketAddr;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
#[cfg(unix)]
|
||||
|
|
@ -11,6 +11,7 @@ use tokio::time::timeout;
|
|||
use tracing::debug;
|
||||
use crate::config::ProxyConfig;
|
||||
use crate::stats::beobachten::BeobachtenStore;
|
||||
use crate::transport::proxy_protocol::{ProxyProtocolV1Builder, ProxyProtocolV2Builder};
|
||||
|
||||
const MASK_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
/// Maximum duration for the entire masking relay.
|
||||
|
|
@ -52,7 +53,7 @@ pub async fn handle_bad_client<R, W>(
|
|||
reader: R,
|
||||
writer: W,
|
||||
initial_data: &[u8],
|
||||
peer_ip: IpAddr,
|
||||
peer: SocketAddr,
|
||||
config: &ProxyConfig,
|
||||
beobachten: &BeobachtenStore,
|
||||
)
|
||||
|
|
@ -63,7 +64,7 @@ where
|
|||
let client_type = detect_client_type(initial_data);
|
||||
if config.general.beobachten {
|
||||
let ttl = Duration::from_secs(config.general.beobachten_minutes.saturating_mul(60));
|
||||
beobachten.record(client_type, peer_ip, ttl);
|
||||
beobachten.record(client_type, peer.ip(), ttl);
|
||||
}
|
||||
|
||||
if !config.censorship.mask {
|
||||
|
|
@ -119,7 +120,44 @@ where
|
|||
let connect_result = timeout(MASK_TIMEOUT, TcpStream::connect(&mask_addr)).await;
|
||||
match connect_result {
|
||||
Ok(Ok(stream)) => {
|
||||
let (mask_read, mask_write) = stream.into_split();
|
||||
let proxy_header: Option<Vec<u8>> = match config.censorship.mask_proxy_protocol {
|
||||
0 => None,
|
||||
version => {
|
||||
let header = if let Ok(local_addr) = stream.local_addr() {
|
||||
match version {
|
||||
2 => match (peer, local_addr) {
|
||||
(SocketAddr::V4(src), SocketAddr::V4(dst)) =>
|
||||
ProxyProtocolV2Builder::new().with_addrs(src.into(), dst.into()).build(),
|
||||
(SocketAddr::V6(src), SocketAddr::V6(dst)) =>
|
||||
ProxyProtocolV2Builder::new().with_addrs(src.into(), dst.into()).build(),
|
||||
_ =>
|
||||
ProxyProtocolV2Builder::new().build(),
|
||||
},
|
||||
_ => match (peer, local_addr) {
|
||||
(SocketAddr::V4(src), SocketAddr::V4(dst)) =>
|
||||
ProxyProtocolV1Builder::new().tcp4(src.into(), dst.into()).build(),
|
||||
(SocketAddr::V6(src), SocketAddr::V6(dst)) =>
|
||||
ProxyProtocolV1Builder::new().tcp6(src.into(), dst.into()).build(),
|
||||
_ =>
|
||||
ProxyProtocolV1Builder::new().build(),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match version {
|
||||
2 => ProxyProtocolV2Builder::new().build(),
|
||||
_ => ProxyProtocolV1Builder::new().build(),
|
||||
}
|
||||
};
|
||||
Some(header)
|
||||
}
|
||||
};
|
||||
|
||||
let (mask_read, mut mask_write) = stream.into_split();
|
||||
if let Some(header) = proxy_header {
|
||||
if mask_write.write_all(&header).await.is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if timeout(MASK_RELAY_TIMEOUT, relay_to_mask(reader, writer, mask_read, mask_write, initial_data)).await.is_err() {
|
||||
debug!("Mask relay timed out");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,14 +233,12 @@ async fn parse_v2<R: AsyncRead + Unpin>(
|
|||
}
|
||||
|
||||
/// Builder for PROXY protocol v1 header
|
||||
#[allow(dead_code)]
|
||||
pub struct ProxyProtocolV1Builder {
|
||||
family: &'static str,
|
||||
src_addr: Option<SocketAddr>,
|
||||
dst_addr: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl ProxyProtocolV1Builder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
|
@ -288,13 +286,11 @@ impl Default for ProxyProtocolV1Builder {
|
|||
}
|
||||
|
||||
/// Builder for PROXY protocol v2 header
|
||||
#[allow(dead_code)]
|
||||
pub struct ProxyProtocolV2Builder {
|
||||
src: Option<SocketAddr>,
|
||||
dst: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl ProxyProtocolV2Builder {
|
||||
pub fn new() -> Self {
|
||||
Self { src: None, dst: None }
|
||||
|
|
|
|||
Loading…
Reference in New Issue