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 size = 0;
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
|
|
||||||
// Retransmit handshake up to 4 times with 1200ms timeout to survive packet loss on mobile
|
// For UoT: TCP is reliable so we don't retry on the same connection.
|
||||||
for attempt in 0..4 {
|
// 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 {
|
if attempt > 0 {
|
||||||
tx.send(UiEvent::Log(format!("Handshake attempt {} lost. Retransmitting...", attempt))).await.ok();
|
tx.send(UiEvent::Log(format!("Handshake attempt {} lost. Retransmitting...", attempt))).await.ok();
|
||||||
}
|
}
|
||||||
send_datagram(&socket, &handshake_frame, self.turn_enabled).await?;
|
send_datagram(&socket, &handshake_frame, self.turn_enabled).await?;
|
||||||
self.metrics.bytes_sent.fetch_add(handshake_frame.len() as u64, Ordering::Relaxed);
|
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)) => {
|
Ok(Ok(n)) => {
|
||||||
size = n;
|
size = n;
|
||||||
success = true;
|
success = true;
|
||||||
|
|
|
||||||
|
|
@ -274,12 +274,41 @@ async fn run_server_loop(
|
||||||
let tcp_map_clone = tcp_map.clone();
|
let tcp_map_clone = tcp_map.clone();
|
||||||
let shared_keys_clone = shared_keys.clone();
|
let shared_keys_clone = shared_keys.clone();
|
||||||
let udp_tx_clone = udp_tx.clone();
|
let udp_tx_clone = udp_tx.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Ok(listener) = tokio::net::TcpListener::bind(&addr).await {
|
if let Ok(listener) = tokio::net::TcpListener::bind(&addr).await {
|
||||||
tracing::info!("TCP (UoT) listener bound to {}", addr);
|
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 {
|
loop {
|
||||||
if let Ok((stream, peer_addr)) = listener.accept().await {
|
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 tm = tcp_map_clone.clone();
|
||||||
let keys = shared_keys_clone.clone();
|
let keys = shared_keys_clone.clone();
|
||||||
let tx = udp_tx_clone.clone();
|
let tx = udp_tx_clone.clone();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue