TLS-F: added Emu + Cache

This commit is contained in:
Alexey 2026-02-20 12:55:26 +03:00
parent e6839adc17
commit 9a907a2470
No known key found for this signature in database
5 changed files with 117 additions and 1 deletions

View File

@ -23,6 +23,7 @@ mod proxy;
mod stats;
mod stream;
mod transport;
mod tls_front;
mod util;
use crate::config::{LogLevel, ProxyConfig};

View File

@ -31,6 +31,7 @@ use crate::stats::{ReplayChecker, Stats};
use crate::stream::{BufferPool, CryptoReader, CryptoWriter};
use crate::transport::middle_proxy::MePool;
use crate::transport::{UpstreamManager, configure_client_socket, parse_proxy_protocol};
use crate::tls_front::TlsFrontCache;
use crate::proxy::direct_relay::handle_via_direct;
use crate::proxy::handshake::{HandshakeSuccess, handle_mtproto_handshake, handle_tls_handshake};
@ -47,6 +48,7 @@ pub async fn handle_client_stream<S>(
buffer_pool: Arc<BufferPool>,
rng: Arc<SecureRandom>,
me_pool: Option<Arc<MePool>>,
tls_cache: Option<Arc<TlsFrontCache>>,
ip_tracker: Arc<UserIpTracker>,
) -> Result<()>
where
@ -111,7 +113,7 @@ where
let (mut tls_reader, tls_writer, _tls_user) = match handle_tls_handshake(
&handshake, read_half, write_half, real_peer,
&config, &replay_checker, &rng,
&config, &replay_checker, &rng, tls_cache.clone(),
).await {
HandshakeResult::Success(result) => result,
HandshakeResult::BadClient { reader, writer } => {
@ -224,6 +226,7 @@ pub struct RunningClientHandler {
buffer_pool: Arc<BufferPool>,
rng: Arc<SecureRandom>,
me_pool: Option<Arc<MePool>>,
tls_cache: Option<Arc<TlsFrontCache>>,
ip_tracker: Arc<UserIpTracker>,
}
@ -238,6 +241,7 @@ impl ClientHandler {
buffer_pool: Arc<BufferPool>,
rng: Arc<SecureRandom>,
me_pool: Option<Arc<MePool>>,
tls_cache: Option<Arc<TlsFrontCache>>,
ip_tracker: Arc<UserIpTracker>,
) -> RunningClientHandler {
RunningClientHandler {
@ -250,6 +254,7 @@ impl ClientHandler {
buffer_pool,
rng,
me_pool,
tls_cache,
ip_tracker,
}
}
@ -367,6 +372,7 @@ impl RunningClientHandler {
&config,
&replay_checker,
&self.rng,
self.tls_cache.clone(),
)
.await
{

View File

@ -1,6 +1,7 @@
//! MTProto Handshake
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use tracing::{debug, warn, trace, info};
use zeroize::Zeroize;
@ -12,6 +13,8 @@ use crate::stream::{FakeTlsReader, FakeTlsWriter, CryptoReader, CryptoWriter};
use crate::error::{ProxyError, HandshakeResult};
use crate::stats::ReplayChecker;
use crate::config::ProxyConfig;
use crate::tls_front::{TlsFrontCache, emulator};
use crate::tls_front::types::CachedTlsData;
/// Result of successful handshake
///

99
src/tls_front/emulator.rs Normal file
View File

@ -0,0 +1,99 @@
use crate::crypto::{sha256_hmac, SecureRandom};
use crate::protocol::constants::{
TLS_RECORD_APPLICATION, TLS_RECORD_CHANGE_CIPHER, TLS_RECORD_HANDSHAKE, TLS_VERSION,
};
use crate::protocol::tls::{TLS_DIGEST_LEN, TLS_DIGEST_POS, gen_fake_x25519_key};
use crate::tls_front::types::CachedTlsData;
/// Build a ServerHello + CCS + ApplicationData sequence using cached TLS metadata.
pub fn build_emulated_server_hello(
secret: &[u8],
client_digest: &[u8; TLS_DIGEST_LEN],
session_id: &[u8],
cached: &CachedTlsData,
rng: &SecureRandom,
) -> Vec<u8> {
// --- ServerHello ---
let mut extensions = Vec::new();
// KeyShare (x25519)
let key = gen_fake_x25519_key(rng);
extensions.extend_from_slice(&0x0033u16.to_be_bytes()); // key_share
extensions.extend_from_slice(&(2 + 2 + 32u16).to_be_bytes()); // len
extensions.extend_from_slice(&0x001du16.to_be_bytes()); // X25519
extensions.extend_from_slice(&(32u16).to_be_bytes());
extensions.extend_from_slice(&key);
// supported_versions (TLS1.3)
extensions.extend_from_slice(&0x002bu16.to_be_bytes());
extensions.extend_from_slice(&(2u16).to_be_bytes());
extensions.extend_from_slice(&0x0304u16.to_be_bytes());
let extensions_len = extensions.len() as u16;
let body_len = 2 + // version
32 + // random
1 + session_id.len() + // session id
2 + // cipher
1 + // compression
2 + extensions.len(); // extensions
let mut message = Vec::with_capacity(4 + body_len);
message.push(0x02); // ServerHello
let len_bytes = (body_len as u32).to_be_bytes();
message.extend_from_slice(&len_bytes[1..4]);
message.extend_from_slice(&cached.server_hello_template.version); // 0x0303
message.extend_from_slice(&[0u8; 32]); // random placeholder
message.push(session_id.len() as u8);
message.extend_from_slice(session_id);
message.extend_from_slice(&cached.server_hello_template.cipher_suite);
message.push(cached.server_hello_template.compression);
message.extend_from_slice(&extensions_len.to_be_bytes());
message.extend_from_slice(&extensions);
let mut server_hello = Vec::with_capacity(5 + message.len());
server_hello.push(TLS_RECORD_HANDSHAKE);
server_hello.extend_from_slice(&TLS_VERSION);
server_hello.extend_from_slice(&(message.len() as u16).to_be_bytes());
server_hello.extend_from_slice(&message);
// --- ChangeCipherSpec ---
let change_cipher_spec = [
TLS_RECORD_CHANGE_CIPHER,
TLS_VERSION[0],
TLS_VERSION[1],
0x00,
0x01,
0x01,
];
// --- ApplicationData (fake encrypted records) ---
let sizes = if cached.app_data_records_sizes.is_empty() {
vec![cached.total_app_data_len.max(1024)]
} else {
cached.app_data_records_sizes.clone()
};
let mut app_data = Vec::new();
for size in sizes {
let mut rec = Vec::with_capacity(5 + size);
rec.push(TLS_RECORD_APPLICATION);
rec.extend_from_slice(&TLS_VERSION);
rec.extend_from_slice(&(size as u16).to_be_bytes());
rec.extend_from_slice(&rng.bytes(size));
app_data.extend_from_slice(&rec);
}
// --- Combine ---
let mut response = Vec::with_capacity(server_hello.len() + change_cipher_spec.len() + app_data.len());
response.extend_from_slice(&server_hello);
response.extend_from_slice(&change_cipher_spec);
response.extend_from_slice(&app_data);
// --- HMAC ---
let mut hmac_input = Vec::with_capacity(TLS_DIGEST_LEN + response.len());
hmac_input.extend_from_slice(client_digest);
hmac_input.extend_from_slice(&response);
let digest = sha256_hmac(secret, &hmac_input);
response[TLS_DIGEST_POS..TLS_DIGEST_POS + TLS_DIGEST_LEN].copy_from_slice(&digest);
response
}

7
src/tls_front/mod.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod types;
pub mod cache;
pub mod fetcher;
pub mod emulator;
pub use cache::TlsFrontCache;
pub use types::{CachedTlsData, TlsFetchResult};