From 7a01d9dfe736616471a45e5f15301b2b8aa24ddc Mon Sep 17 00:00:00 2001 From: yeoleobun Date: Tue, 17 Mar 2026 20:04:53 +0800 Subject: [PATCH 1/2] fix: reject stun for rtp --- src/transports/ice/mod.rs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/transports/ice/mod.rs b/src/transports/ice/mod.rs index ebeec56..64724af 100644 --- a/src/transports/ice/mod.rs +++ b/src/transports/ice/mod.rs @@ -18,7 +18,7 @@ use anyhow::{Context, Result, anyhow, bail}; use tokio::net::{UdpSocket, lookup_host}; use tokio::sync::{Mutex, broadcast, mpsc, oneshot, watch}; use tokio::time::timeout; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument, trace, warn}; #[cfg(any(test, feature = "simulator"))] use self::stun::random_u32; @@ -1219,6 +1219,17 @@ async fn handle_packet( match StunMessage::decode(packet) { Ok(msg) => { if msg.class == StunClass::Request { + if inner.config.transport_mode == crate::TransportMode::Rtp + && !inner.config.enable_ice_lite + { + warn!( + remote_addr = %addr, + method = ?msg.method, + class = ?msg.class, + "Rejecting STUN on RTP transport without ICE-lite" + ); + return; + } // Start of Latching Logic for RTP mode if inner.config.transport_mode == crate::TransportMode::Rtp && inner.config.enable_latching @@ -1976,13 +1987,29 @@ impl IceGatherer { async fn bind_socket(&self, ip: IpAddr) -> Result { if let (Some(start), Some(end)) = (self.config.rtp_start_port, self.config.rtp_end_port) { - for port in start..=end { + let start = start.saturating_add(start % 2); + let end = end - (end % 2); + + if start > end { + bail!("No usable even RTP ports in range {}..={}", start, end); + } + + let port_count = (((end - start) / 2) + 1) as u64; + let start_index = (random_u64() % port_count) as u16; + let mut port = start + (start_index * 2); + + for _ in 0..port_count { match UdpSocket::bind(SocketAddr::new(ip, port)).await { Ok(socket) => return Ok(socket), - Err(_) => continue, + Err(_) => { + port = port.saturating_add(2); + if port > end { + port = start; + } + } } } - bail!("No available ports in range {}..{}", start, end) + bail!("No available even RTP ports in range {}..={}", start, end) } else { UdpSocket::bind(SocketAddr::new(ip, 0)) .await From 01ab52e356a53981e626b78ab2ae880a7c73a107 Mon Sep 17 00:00:00 2001 From: yeoleobun Date: Tue, 17 Mar 2026 20:38:12 +0800 Subject: [PATCH 2/2] improve: remove duplicated latching --- src/transports/ice/conn.rs | 13 +++++++------ src/transports/ice/mod.rs | 31 ------------------------------- 2 files changed, 7 insertions(+), 37 deletions(-) diff --git a/src/transports/ice/conn.rs b/src/transports/ice/conn.rs index 377c168..378aa1f 100644 --- a/src/transports/ice/conn.rs +++ b/src/transports/ice/conn.rs @@ -16,6 +16,7 @@ pub struct IceConn { pub dtls_receiver: RwLock>>, pub rtp_receiver: RwLock>>, pub latch_on_rtp: AtomicBool, + pub rtp_latched: AtomicBool, } impl IceConn { @@ -30,6 +31,7 @@ impl IceConn { dtls_receiver: RwLock::new(None), rtp_receiver: RwLock::new(None), latch_on_rtp: AtomicBool::new(false), + rtp_latched: AtomicBool::new(false), }) } @@ -164,13 +166,12 @@ impl PacketReceiver for IceConn { } } else if (128..192).contains(&first_byte) { // RTP / RTCP - if self.latch_on_rtp.load(Ordering::Relaxed) && addr != current_remote { + if self.latch_on_rtp.load(Ordering::Relaxed) + && addr != current_remote + && !self.rtp_latched.load(Ordering::Relaxed) + { *self.remote_addr.write().unwrap() = addr; - let current_rtcp = *self.remote_rtcp_addr.read().unwrap(); - if let Some(mut rtcp_addr) = current_rtcp { - rtcp_addr.set_ip(addr.ip()); - *self.remote_rtcp_addr.write().unwrap() = Some(rtcp_addr); - } + self.rtp_latched.store(true, Ordering::Relaxed); } let receiver = { let rx_lock = self.rtp_receiver.read().unwrap(); diff --git a/src/transports/ice/mod.rs b/src/transports/ice/mod.rs index 64724af..6bd327c 100644 --- a/src/transports/ice/mod.rs +++ b/src/transports/ice/mod.rs @@ -1230,37 +1230,6 @@ async fn handle_packet( ); return; } - // Start of Latching Logic for RTP mode - if inner.config.transport_mode == crate::TransportMode::Rtp - && inner.config.enable_latching - { - let mut update = false; - { - let selected_pair = inner.selected_pair.lock().unwrap(); - if let Some(pair) = selected_pair.as_ref() { - if pair.remote.address != addr - && msg.method == StunMethod::Binding - && pair.remote.address.port() == addr.port() - // Match port only - { - debug!( - "RTP Latching: Switching remote address from {} to {} based on STUN Binding Request", - pair.remote.address, addr - ); - update = true; - } - } - } - - if update { - let mut pair = inner.selected_pair.lock().unwrap().clone().unwrap(); - pair.remote.address = addr; - - *inner.selected_pair.lock().unwrap() = Some(pair.clone()); - // This send should trigger the pair_monitor in PeerConnection via watcher - let _ = inner.selected_pair_notifier.send(Some(pair.clone())); - } - } handle_stun_request(&sender, &msg, addr, inner).await; } else if msg.class == StunClass::SuccessResponse { let mut map = inner.pending_transactions.lock().unwrap();