TLS-F Fetching Optimization

This commit is contained in:
Alexey 2026-02-26 19:35:34 +03:00
parent 4eebb4feb2
commit 04e6135935
No known key found for this signature in database
1 changed files with 127 additions and 72 deletions

View File

@ -254,6 +254,133 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
warn!("Using default tls_domain. Consider setting a custom domain."); warn!("Using default tls_domain. Consider setting a custom domain.");
} }
let upstream_manager = Arc::new(UpstreamManager::new(config.upstreams.clone()));
let mut tls_domains = Vec::with_capacity(1 + config.censorship.tls_domains.len());
tls_domains.push(config.censorship.tls_domain.clone());
for d in &config.censorship.tls_domains {
if !tls_domains.contains(d) {
tls_domains.push(d.clone());
}
}
// Start TLS front fetching in background immediately, in parallel with STUN probing.
let tls_cache: Option<Arc<TlsFrontCache>> = if config.censorship.tls_emulation {
let cache = Arc::new(TlsFrontCache::new(
&tls_domains,
config.censorship.fake_cert_len,
&config.censorship.tls_front_dir,
));
cache.load_from_disk().await;
let port = config.censorship.mask_port;
let proxy_protocol = config.censorship.mask_proxy_protocol;
let mask_host = config
.censorship
.mask_host
.clone()
.unwrap_or_else(|| config.censorship.tls_domain.clone());
let fetch_timeout = Duration::from_secs(5);
let cache_initial = cache.clone();
let domains_initial = tls_domains.clone();
let host_initial = mask_host.clone();
let upstream_initial = upstream_manager.clone();
tokio::spawn(async move {
let mut join = tokio::task::JoinSet::new();
for domain in domains_initial {
let cache_domain = cache_initial.clone();
let host_domain = host_initial.clone();
let upstream_domain = upstream_initial.clone();
join.spawn(async move {
match crate::tls_front::fetcher::fetch_real_tls(
&host_domain,
port,
&domain,
fetch_timeout,
Some(upstream_domain),
proxy_protocol,
)
.await
{
Ok(res) => cache_domain.update_from_fetch(&domain, res).await,
Err(e) => {
warn!(domain = %domain, error = %e, "TLS emulation initial fetch failed")
}
}
});
}
while let Some(res) = join.join_next().await {
if let Err(e) = res {
warn!(error = %e, "TLS emulation initial fetch task join failed");
}
}
});
let cache_timeout = cache.clone();
let domains_timeout = tls_domains.clone();
let fake_cert_len = config.censorship.fake_cert_len;
tokio::spawn(async move {
tokio::time::sleep(fetch_timeout).await;
for domain in domains_timeout {
let cached = cache_timeout.get(&domain).await;
if cached.domain == "default" {
warn!(
domain = %domain,
timeout_secs = fetch_timeout.as_secs(),
fake_cert_len,
"TLS-front fetch not ready within timeout; using cache/default fake cert fallback"
);
}
}
});
// Periodic refresh with jitter.
let cache_refresh = cache.clone();
let domains_refresh = tls_domains.clone();
let host_refresh = mask_host.clone();
let upstream_refresh = upstream_manager.clone();
tokio::spawn(async move {
loop {
let base_secs = rand::rng().random_range(4 * 3600..=6 * 3600);
let jitter_secs = rand::rng().random_range(0..=7200);
tokio::time::sleep(Duration::from_secs(base_secs + jitter_secs)).await;
let mut join = tokio::task::JoinSet::new();
for domain in domains_refresh.clone() {
let cache_domain = cache_refresh.clone();
let host_domain = host_refresh.clone();
let upstream_domain = upstream_refresh.clone();
join.spawn(async move {
match crate::tls_front::fetcher::fetch_real_tls(
&host_domain,
port,
&domain,
fetch_timeout,
Some(upstream_domain),
proxy_protocol,
)
.await
{
Ok(res) => cache_domain.update_from_fetch(&domain, res).await,
Err(e) => warn!(domain = %domain, error = %e, "TLS emulation refresh failed"),
}
});
}
while let Some(res) = join.join_next().await {
if let Err(e) = res {
warn!(error = %e, "TLS emulation refresh task join failed");
}
}
}
});
Some(cache)
} else {
None
};
let probe = run_probe( let probe = run_probe(
&config.network, &config.network,
config.general.middle_proxy_nat_probe, config.general.middle_proxy_nat_probe,
@ -450,80 +577,8 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
Duration::from_secs(config.access.replay_window_secs), Duration::from_secs(config.access.replay_window_secs),
)); ));
let upstream_manager = Arc::new(UpstreamManager::new(config.upstreams.clone()));
let buffer_pool = Arc::new(BufferPool::with_config(16 * 1024, 4096)); let buffer_pool = Arc::new(BufferPool::with_config(16 * 1024, 4096));
// TLS front cache (optional emulation)
let mut tls_domains = Vec::with_capacity(1 + config.censorship.tls_domains.len());
tls_domains.push(config.censorship.tls_domain.clone());
for d in &config.censorship.tls_domains {
if !tls_domains.contains(d) {
tls_domains.push(d.clone());
}
}
let tls_cache: Option<Arc<TlsFrontCache>> = if config.censorship.tls_emulation {
let cache = Arc::new(TlsFrontCache::new(
&tls_domains,
config.censorship.fake_cert_len,
&config.censorship.tls_front_dir,
));
cache.load_from_disk().await;
let port = config.censorship.mask_port;
let mask_host = config.censorship.mask_host.clone()
.unwrap_or_else(|| config.censorship.tls_domain.clone());
// Initial synchronous fetch to warm cache before serving clients.
for domain in tls_domains.clone() {
match crate::tls_front::fetcher::fetch_real_tls(
&mask_host,
port,
&domain,
Duration::from_secs(5),
Some(upstream_manager.clone()),
config.censorship.mask_proxy_protocol,
)
.await
{
Ok(res) => cache.update_from_fetch(&domain, res).await,
Err(e) => warn!(domain = %domain, error = %e, "TLS emulation fetch failed"),
}
}
// Periodic refresh with jitter.
let cache_clone = cache.clone();
let domains = tls_domains.clone();
let upstream_for_task = upstream_manager.clone();
let proxy_protocol = config.censorship.mask_proxy_protocol;
tokio::spawn(async move {
loop {
let base_secs = rand::rng().random_range(4 * 3600..=6 * 3600);
let jitter_secs = rand::rng().random_range(0..=7200);
tokio::time::sleep(Duration::from_secs(base_secs + jitter_secs)).await;
for domain in &domains {
match crate::tls_front::fetcher::fetch_real_tls(
&mask_host,
port,
domain,
Duration::from_secs(5),
Some(upstream_for_task.clone()),
proxy_protocol,
)
.await
{
Ok(res) => cache_clone.update_from_fetch(domain, res).await,
Err(e) => warn!(domain = %domain, error = %e, "TLS emulation refresh failed"),
}
}
}
});
Some(cache)
} else {
None
};
// Middle-End ping before DC connectivity // Middle-End ping before DC connectivity
if let Some(ref pool) = me_pool { if let Some(ref pool) = me_pool {
let me_results = run_me_ping(pool, &rng).await; let me_results = run_me_ping(pool, &rng).await;