ME NoWait Routing + Upstream Connbudget + PROXY Header t/o + allocation cuts

This commit is contained in:
Alexey
2026-03-06 03:58:08 +03:00
parent 8f3bdaec2c
commit f32c34f126
15 changed files with 279 additions and 49 deletions

View File

@@ -97,8 +97,11 @@ where
.unwrap_or_else(|_| "0.0.0.0:443".parse().unwrap());
if proxy_protocol_enabled {
match parse_proxy_protocol(&mut stream, peer).await {
Ok(info) => {
let proxy_header_timeout = Duration::from_millis(
config.server.proxy_protocol_header_timeout_ms.max(1),
);
match timeout(proxy_header_timeout, parse_proxy_protocol(&mut stream, peer)).await {
Ok(Ok(info)) => {
debug!(
peer = %peer,
client = %info.src_addr,
@@ -110,12 +113,18 @@ where
local_addr = dst;
}
}
Err(e) => {
Ok(Err(e)) => {
stats.increment_connects_bad();
warn!(peer = %peer, error = %e, "Invalid PROXY protocol header");
record_beobachten_class(&beobachten, &config, peer.ip(), "other");
return Err(e);
}
Err(_) => {
stats.increment_connects_bad();
warn!(peer = %peer, timeout_ms = proxy_header_timeout.as_millis(), "PROXY protocol header timeout");
record_beobachten_class(&beobachten, &config, peer.ip(), "other");
return Err(ProxyError::InvalidProxyProtocol);
}
}
}
@@ -161,7 +170,7 @@ where
let (read_half, write_half) = tokio::io::split(stream);
let (mut tls_reader, tls_writer, _tls_user) = match handle_tls_handshake(
let (mut tls_reader, tls_writer, tls_user) = match handle_tls_handshake(
&handshake, read_half, write_half, real_peer,
&config, &replay_checker, &rng, tls_cache.clone(),
).await {
@@ -190,7 +199,7 @@ where
let (crypto_reader, crypto_writer, success) = match handle_mtproto_handshake(
&mtproto_handshake, tls_reader, tls_writer, real_peer,
&config, &replay_checker, true,
&config, &replay_checker, true, Some(tls_user.as_str()),
).await {
HandshakeResult::Success(result) => result,
HandshakeResult::BadClient { reader: _, writer: _ } => {
@@ -234,7 +243,7 @@ where
let (crypto_reader, crypto_writer, success) = match handle_mtproto_handshake(
&handshake, read_half, write_half, real_peer,
&config, &replay_checker, false,
&config, &replay_checker, false, None,
).await {
HandshakeResult::Success(result) => result,
HandshakeResult::BadClient { reader, writer } => {
@@ -415,8 +424,16 @@ impl RunningClientHandler {
let mut local_addr = self.stream.local_addr().map_err(ProxyError::Io)?;
if self.proxy_protocol_enabled {
match parse_proxy_protocol(&mut self.stream, self.peer).await {
Ok(info) => {
let proxy_header_timeout = Duration::from_millis(
self.config.server.proxy_protocol_header_timeout_ms.max(1),
);
match timeout(
proxy_header_timeout,
parse_proxy_protocol(&mut self.stream, self.peer),
)
.await
{
Ok(Ok(info)) => {
debug!(
peer = %self.peer,
client = %info.src_addr,
@@ -428,7 +445,7 @@ impl RunningClientHandler {
local_addr = dst;
}
}
Err(e) => {
Ok(Err(e)) => {
self.stats.increment_connects_bad();
warn!(peer = %self.peer, error = %e, "Invalid PROXY protocol header");
record_beobachten_class(
@@ -439,6 +456,21 @@ impl RunningClientHandler {
);
return Err(e);
}
Err(_) => {
self.stats.increment_connects_bad();
warn!(
peer = %self.peer,
timeout_ms = proxy_header_timeout.as_millis(),
"PROXY protocol header timeout"
);
record_beobachten_class(
&self.beobachten,
&self.config,
self.peer.ip(),
"other",
);
return Err(ProxyError::InvalidProxyProtocol);
}
}
}
@@ -494,7 +526,7 @@ impl RunningClientHandler {
let (read_half, write_half) = self.stream.into_split();
let (mut tls_reader, tls_writer, _tls_user) = match handle_tls_handshake(
let (mut tls_reader, tls_writer, tls_user) = match handle_tls_handshake(
&handshake,
read_half,
write_half,
@@ -538,6 +570,7 @@ impl RunningClientHandler {
&config,
&replay_checker,
true,
Some(tls_user.as_str()),
)
.await
{
@@ -611,6 +644,7 @@ impl RunningClientHandler {
&config,
&replay_checker,
false,
None,
)
.await
{

View File

@@ -34,7 +34,7 @@ where
let user = &success.user;
let dc_addr = get_dc_addr_static(success.dc_idx, &config)?;
info!(
debug!(
user = %user,
peer = %success.peer,
dc = success.dc_idx,

View File

@@ -6,7 +6,7 @@ use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use tracing::{debug, warn, trace, info};
use tracing::{debug, warn, trace};
use zeroize::Zeroize;
use crate::crypto::{sha256, AesCtr, SecureRandom};
@@ -19,6 +19,31 @@ use crate::stats::ReplayChecker;
use crate::config::ProxyConfig;
use crate::tls_front::{TlsFrontCache, emulator};
fn decode_user_secrets(
config: &ProxyConfig,
preferred_user: Option<&str>,
) -> Vec<(String, Vec<u8>)> {
let mut secrets = Vec::with_capacity(config.access.users.len());
if let Some(preferred) = preferred_user
&& let Some(secret_hex) = config.access.users.get(preferred)
&& let Ok(bytes) = hex::decode(secret_hex)
{
secrets.push((preferred.to_string(), bytes));
}
for (name, secret_hex) in &config.access.users {
if preferred_user.is_some_and(|preferred| preferred == name.as_str()) {
continue;
}
if let Ok(bytes) = hex::decode(secret_hex) {
secrets.push((name.clone(), bytes));
}
}
secrets
}
/// Result of successful handshake
///
/// Key material (`dec_key`, `dec_iv`, `enc_key`, `enc_iv`) is
@@ -82,11 +107,7 @@ where
return HandshakeResult::BadClient { reader, writer };
}
let secrets: Vec<(String, Vec<u8>)> = config.access.users.iter()
.filter_map(|(name, hex)| {
hex::decode(hex).ok().map(|bytes| (name.clone(), bytes))
})
.collect();
let secrets = decode_user_secrets(config, None);
let validation = match tls::validate_tls_handshake(
handshake,
@@ -201,7 +222,7 @@ where
return HandshakeResult::Error(ProxyError::Io(e));
}
info!(
debug!(
peer = %peer,
user = %validation.user,
"TLS handshake successful"
@@ -223,6 +244,7 @@ pub async fn handle_mtproto_handshake<R, W>(
config: &ProxyConfig,
replay_checker: &ReplayChecker,
is_tls: bool,
preferred_user: Option<&str>,
) -> HandshakeResult<(CryptoReader<R>, CryptoWriter<W>, HandshakeSuccess), R, W>
where
R: AsyncRead + Unpin + Send,
@@ -239,11 +261,9 @@ where
let enc_prekey_iv: Vec<u8> = dec_prekey_iv.iter().rev().copied().collect();
for (user, secret_hex) in &config.access.users {
let secret = match hex::decode(secret_hex) {
Ok(s) => s,
Err(_) => continue,
};
let decoded_users = decode_user_secrets(config, preferred_user);
for (user, secret) in decoded_users {
let dec_prekey = &dec_prekey_iv[..PREKEY_LEN];
let dec_iv_bytes = &dec_prekey_iv[PREKEY_LEN..];
@@ -311,7 +331,7 @@ where
is_tls,
};
info!(
debug!(
peer = %peer,
user = %user,
dc = dc_idx,

View File

@@ -8,7 +8,7 @@ use std::time::{Duration, Instant};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::sync::{mpsc, oneshot};
use tracing::{debug, info, trace, warn};
use tracing::{debug, trace, warn};
use crate::config::ProxyConfig;
use crate::crypto::SecureRandom;
@@ -210,7 +210,7 @@ where
let proto_tag = success.proto_tag;
let pool_generation = me_pool.current_generation();
info!(
debug!(
user = %user,
peer = %peer,
dc = success.dc_idx,