mirror of https://github.com/ospab/ostp.git
fix: noise-read in UoT handshake (single attempt, 4s timeout); add TCP rate limiter against bots
This commit is contained in:
parent
be55aa6c6f
commit
1cff291fdd
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -278,8 +278,37 @@ async fn run_server_loop(
|
|||
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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue