From 054d863a6a3d0eade1d9678fa9fc5f16576780ba Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 4 Sep 2026 18:03:17 +0800 Subject: [PATCH] port_forward_mux: pin permission revocation and whole-tunnel failure in tests Both already hold; the review asked for them to be stated. `enable-tunnel` turned off mid-session refuses the next `open` while the live channel keeps relaying, and a dead tunnel ends every channel on it together, after which the next accept establishes again on the same `Tunnel`. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EZ49AbZJYfm8NTp5yDPMab --- src/port_forward_mux.rs | 21 +++++++++++++++++---- src/server/port_forward_mux.rs | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/port_forward_mux.rs b/src/port_forward_mux.rs index 6ac418605..63e060bf6 100644 --- a/src/port_forward_mux.rs +++ b/src/port_forward_mux.rs @@ -1311,14 +1311,27 @@ mod tests { let t = Tunnel::new(); t.claim(); let h = t.set_muxed(ours, NoUi::default()); - let (mut app, sock) = local_pair().await; - h.open("localhost", 1, sock, vec![]).unwrap(); + let (mut app_a, sock_a) = local_pair().await; + let (mut app_b, sock_b) = local_pair().await; + h.open("localhost", 1, sock_a, vec![]).unwrap(); + h.open("localhost", 1, sock_b, vec![]).unwrap(); drop(peer); + // One tunnel is one failure domain: every channel on it ends. let mut buf = [0u8; 1]; - assert_eq!(app.read(&mut buf).await.unwrap(), 0); + assert_eq!(app_a.read(&mut buf).await.unwrap(), 0); + assert_eq!(app_b.read(&mut buf).await.unwrap(), 0); tokio::time::sleep(std::time::Duration::from_millis(50)).await; - assert!(matches!(t.claim(), Claim::Claimed)); assert!(h.open("localhost", 1, local_pair().await.1, vec![]).is_err()); + // The next accept establishes again on the same `Tunnel`. + assert!(matches!(t.claim(), Claim::Claimed)); + let (ours, mut peer) = stream_pair().await; + let h = t.set_muxed(ours, NoUi::default()); + let (_app_c, sock_c) = local_pair().await; + h.open("localhost", 1, sock_c, vec![]).unwrap(); + assert!(matches!( + recv_frame(&mut peer).await.union, + Some(port_forward_channel::Union::Open(_)) + )); }); } diff --git a/src/server/port_forward_mux.rs b/src/server/port_forward_mux.rs index 428d50679..d6f22e2d8 100644 --- a/src/server/port_forward_mux.rs +++ b/src/server/port_forward_mux.rs @@ -381,6 +381,24 @@ mod tests { }); } + #[test] + fn a_revoked_permission_refuses_new_channels_and_keeps_live_ones() { + rt().block_on(async { + let port = echo_target().await; + let (tx, mut rx) = mpsc::unbounded_channel(); + let mut mux = PortForwardMux::new(tx, format!("127.0.0.1:{}", port)); + mux.handle(open(1, port), || true); + assert_eq!(opened(&next_frame(&mut rx).await), (1, true)); + // `enable-tunnel` is consulted per `open`, so turning it off + // mid-session stops new channels; the live one keeps relaying. + mux.handle(open(2, port), || false); + assert_eq!(opened(&next_frame(&mut rx).await), (2, false)); + mux.handle(data(1, b"still relayed"), || false); + assert_eq!(data_of(&next_frame(&mut rx).await), (1, b"still relayed".to_vec())); + assert_eq!(mux.live_channels(), 1); + }); + } + #[test] fn close_while_connecting_sends_no_opened() { rt().block_on(async {