fix: noise-read in UoT handshake (single attempt, 4s timeout); add TCP rate limiter against bots

This commit is contained in:
ospab 2026-05-21 15:15:56 +03:00
parent be55aa6c6f
commit 1cff291fdd
2 changed files with 39 additions and 4 deletions

View File

@ -886,15 +886,21 @@ impl Bridge {
let mut size = 0;
let mut success = false;
// Retransmit handshake up to 4 times with 1200ms timeout to survive packet loss on mobile
for attempt in 0..4 {
// For UoT: TCP is reliable so we don't retry on the same connection.
// Multiple retries would cause stale Noise responses to queue in the mpsc channel
// and break the Noise state machine (noise-read error).
// For UDP: retry up to 4x with 1200ms timeout to survive packet loss.
let is_uot = matches!(socket, crate::transport::Transport::Uot { .. });
let (attempt_limit, attempt_timeout_ms) = if is_uot { (1, 4000) } else { (4, 1200) };
for attempt in 0..attempt_limit {
if attempt > 0 {
tx.send(UiEvent::Log(format!("Handshake attempt {} lost. Retransmitting...", attempt))).await.ok();
}
send_datagram(&socket, &handshake_frame, self.turn_enabled).await?;
self.metrics.bytes_sent.fetch_add(handshake_frame.len() as u64, Ordering::Relaxed);
match timeout(Duration::from_millis(1200), socket.recv(&mut buf)).await {
match timeout(Duration::from_millis(attempt_timeout_ms), socket.recv(&mut buf)).await {
Ok(Ok(n)) => {
size = n;
success = true;

View File

@ -274,12 +274,41 @@ async fn run_server_loop(
let tcp_map_clone = tcp_map.clone();
let shared_keys_clone = shared_keys.clone();
let udp_tx_clone = udp_tx.clone();
tokio::spawn(async move {
if let Ok(listener) = tokio::net::TcpListener::bind(&addr).await {
tracing::info!("TCP (UoT) listener bound to {}", addr);
// Rate limiter: track connection attempts per IP
// Map<IP, (count, window_start)>
let rate_map: std::sync::Arc<tokio::sync::Mutex<std::collections::HashMap<std::net::IpAddr, (u32, std::time::Instant)>>> =
std::sync::Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new()));
const RATE_WINDOW_SECS: u64 = 10;
const RATE_MAX_CONNS: u32 = 10;
loop {
if let Ok((stream, peer_addr)) = listener.accept().await {
// Rate limit check
let peer_ip = peer_addr.ip();
let allowed = {
let mut map = rate_map.lock().await;
let now = std::time::Instant::now();
let entry = map.entry(peer_ip).or_insert((0, now));
if now.duration_since(entry.1).as_secs() >= RATE_WINDOW_SECS {
// Reset window
*entry = (1, now);
true
} else {
entry.0 += 1;
entry.0 <= RATE_MAX_CONNS
}
};
if !allowed {
tracing::debug!("UoT rate limit exceeded for {}, dropping connection", peer_ip);
continue;
}
let tm = tcp_map_clone.clone();
let keys = shared_keys_clone.clone();
let tx = udp_tx_clone.clone();