mirror of https://github.com/ospab/ostp.git
fix(client): stabilize UDP sessions - prevent crashes on transient recv errors in udp_nat and proxy
This commit is contained in:
parent
6b58e0e8f3
commit
38f1752fda
|
|
@ -371,11 +371,19 @@ async fn handle_udp_associate(
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
res = client_tcp.read(&mut tcp_buf) => {
|
res = client_tcp.read(&mut tcp_buf) => {
|
||||||
let n = res?;
|
match res {
|
||||||
if n == 0 { break; }
|
Ok(0) | Err(_) => break,
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res = sock_rx.recv_from(&mut buf) => {
|
res = sock_rx.recv_from(&mut buf) => {
|
||||||
let (len, addr) = res?;
|
let (len, addr) = match res {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::debug!("udp_associate recv_from error: {}", e);
|
||||||
|
continue; // transient error, don't kill the session
|
||||||
|
}
|
||||||
|
};
|
||||||
{
|
{
|
||||||
let mut guard = client_udp_addr.lock().unwrap();
|
let mut guard = client_udp_addr.lock().unwrap();
|
||||||
if guard.is_none() {
|
if guard.is_none() {
|
||||||
|
|
|
||||||
|
|
@ -96,13 +96,8 @@ async fn start_udp_session(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let udp = match relay_addr {
|
// Local SOCKS5 proxy always returns 127.0.0.1 (IPv4), so always bind IPv4
|
||||||
SocketAddr::V4(_) => UdpSocket::bind("127.0.0.1:0").await?,
|
let udp = UdpSocket::bind("127.0.0.1:0").await?;
|
||||||
SocketAddr::V6(_) => match UdpSocket::bind("[::1]:0").await {
|
|
||||||
Ok(sock) => sock,
|
|
||||||
Err(_) => UdpSocket::bind("[::]:0").await?,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut buf = vec![0u8; 65536];
|
let mut buf = vec![0u8; 65536];
|
||||||
|
|
||||||
|
|
@ -128,36 +123,45 @@ async fn start_udp_session(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res = udp.recv_from(&mut buf) => {
|
res = udp.recv_from(&mut buf) => {
|
||||||
let (len, _peer) = res?;
|
match res {
|
||||||
if len < 10 { continue; } // At least 10 bytes for SOCKS5 header
|
Err(e) => {
|
||||||
let frag = buf[2];
|
tracing::debug!("udp_nat recv_from error: {}", e);
|
||||||
if frag != 0 { continue; } // fragment not supported
|
continue; // transient error, don't kill the session
|
||||||
let atyp = buf[3];
|
|
||||||
let (header_len, remote_dst) = match atyp {
|
|
||||||
1 => {
|
|
||||||
if len < 10 { continue; }
|
|
||||||
let ip = std::net::Ipv4Addr::new(buf[4], buf[5], buf[6], buf[7]);
|
|
||||||
let port = u16::from_be_bytes([buf[8], buf[9]]);
|
|
||||||
(10, SocketAddr::new(std::net::IpAddr::V4(ip), port))
|
|
||||||
}
|
}
|
||||||
4 => {
|
Ok((len, _peer)) => {
|
||||||
if len < 22 { continue; }
|
if len < 4 { continue; }
|
||||||
let mut octets = [0u8; 16];
|
let frag = buf[2];
|
||||||
octets.copy_from_slice(&buf[4..20]);
|
if frag != 0 { continue; } // fragment not supported
|
||||||
let ip = std::net::Ipv6Addr::from(octets);
|
let atyp = buf[3];
|
||||||
let port = u16::from_be_bytes([buf[20], buf[21]]);
|
let (header_len, remote_dst) = match atyp {
|
||||||
(22, SocketAddr::new(std::net::IpAddr::V6(ip), port))
|
1 => {
|
||||||
|
if len < 10 { continue; }
|
||||||
|
let ip = std::net::Ipv4Addr::new(buf[4], buf[5], buf[6], buf[7]);
|
||||||
|
let port = u16::from_be_bytes([buf[8], buf[9]]);
|
||||||
|
(10, SocketAddr::new(std::net::IpAddr::V4(ip), port))
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
if len < 22 { continue; }
|
||||||
|
let mut octets = [0u8; 16];
|
||||||
|
octets.copy_from_slice(&buf[4..20]);
|
||||||
|
let ip = std::net::Ipv6Addr::from(octets);
|
||||||
|
let port = u16::from_be_bytes([buf[20], buf[21]]);
|
||||||
|
(22, SocketAddr::new(std::net::IpAddr::V6(ip), port))
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
let payload = buf[header_len..len].to_vec();
|
||||||
|
use futures::SinkExt;
|
||||||
|
let _ = smoltcp_tx.lock().await.send((payload, remote_dst, client_src)).await;
|
||||||
}
|
}
|
||||||
_ => continue, // Domain name not supported for incoming packets in typical UDP associate
|
}
|
||||||
};
|
|
||||||
let payload = buf[header_len..len].to_vec();
|
|
||||||
use futures::SinkExt;
|
|
||||||
let _ = smoltcp_tx.lock().await.send((payload, remote_dst, client_src)).await;
|
|
||||||
}
|
}
|
||||||
// If TCP drops, UDP association is over
|
// If TCP drops, UDP association is over
|
||||||
res = tcp.read(&mut tcp_buf) => {
|
res = tcp.read(&mut tcp_buf) => {
|
||||||
let n = res?;
|
match res {
|
||||||
if n == 0 { break; }
|
Ok(0) | Err(_) => break,
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue