From c42d74540fe6521454df0bf9e6971282683e0534 Mon Sep 17 00:00:00 2001 From: kanpov Date: Sat, 6 Jul 2024 11:57:17 +0300 Subject: [PATCH 1/9] Begin groundwork on streamlocal-forward --- russh/src/client/encrypted.rs | 25 +++++++++++ russh/src/client/mod.rs | 11 +++++ russh/src/client/session.rs | 42 +++++++++++++++++++ russh/src/parsing.rs | 7 ++++ russh/src/server/encrypted.rs | 36 ++++++++++++++++ russh/src/server/mod.rs | 31 ++++++++++++++ russh/src/server/session.rs | 79 +++++++++++++++++++++++++++++++++++ russh/src/session.rs | 2 + 8 files changed, 233 insertions(+) diff --git a/russh/src/client/encrypted.rs b/russh/src/client/encrypted.rs index 280dda9e..44229f7c 100644 --- a/russh/src/client/encrypted.rs +++ b/russh/src/client/encrypted.rs @@ -806,6 +806,18 @@ impl Session { ) .await? } + ChannelType::ForwardedStreamLocal(d) => { + confirm(); + let channel = self.accept_server_initiated_channel(id, &msg); + client + .server_channel_open_forwarded_streamlocal( + channel, + &d.server_socket_path, + &d.client_socket_path, + self, + ) + .await?; + } ChannelType::AgentForward => { confirm(); client.server_channel_open_agent_forward(id, self).await? @@ -849,6 +861,13 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(true); } + Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { + // NEED HELP: how to do this? + let _ = return_channel.send(None); + } + Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { + let _ = return_channel.send(true); + } None => { error!("Received global request failure for unknown request!") } @@ -867,6 +886,12 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(false); } + Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { + let _ = return_channel.send(None); + } + Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { + let _ = return_channel.send(false); + } None => { error!("Received global request failure for unknown request!") } diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index aec12cd2..d0a4bde0 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -1553,6 +1553,17 @@ pub trait Handler: Sized + Send { Ok(()) } + #[allow(unused_variables)] + async fn server_channel_open_forwarded_streamlocal( + &mut self, + channel: Channel, + remote_socket_path: &str, + local_socket_path: &str, + session: &mut Session, + ) -> Result<(), Self::Error> { + Ok(()) + } + /// Called when the server opens an agent forwarding channel #[allow(unused_variables)] async fn server_channel_open_agent_forward( diff --git a/russh/src/client/session.rs b/russh/src/client/session.rs index 4c93d1ad..83dc9a12 100644 --- a/russh/src/client/session.rs +++ b/russh/src/client/session.rs @@ -319,6 +319,48 @@ impl Session { } } + pub fn streamlocal_forward( + &mut self, + reply_channel: Option>>, + socket_path: &str, + ) { + if let Some(ref mut enc) = self.common.encrypted { + let want_reply = reply_channel.is_some(); + if let Some(reply_channel) = reply_channel { + self.open_global_requests.push_back( + crate::session::GlobalRequestResponse::StreamLocalForward(reply_channel), + ); + } + push_packet!(enc.write, { + enc.write.push(msg::GLOBAL_REQUEST); + enc.write.extend_ssh_string(b"streamlocal-forward"); + enc.write.push(want_reply as u8); + enc.write.extend_ssh_string(socket_path.as_bytes()); + }); + } + } + + pub fn cancel_streamlocal_forward( + &mut self, + reply_channel: Option>, + socket_path: &str, + ) { + if let Some(ref mut enc) = self.common.encrypted { + let want_reply = reply_channel.is_some(); + if let Some(reply_channel) = reply_channel { + self.open_global_requests.push_back( + crate::session::GlobalRequestResponse::CancelStreamLocalForward(reply_channel), + ); + } + push_packet!(enc.write, { + enc.write.push(msg::GLOBAL_REQUEST); + enc.write.extend_ssh_string(b"cancel-streamlocal-forward"); + enc.write.push(want_reply as u8); + enc.write.extend_ssh_string(socket_path.as_bytes()); + }); + } + } + pub fn send_keepalive(&mut self, want_reply: bool) { self.open_global_requests .push_back(crate::session::GlobalRequestResponse::Keepalive); diff --git a/russh/src/parsing.rs b/russh/src/parsing.rs index 77f84e07..04e07ba1 100644 --- a/russh/src/parsing.rs +++ b/russh/src/parsing.rs @@ -93,6 +93,7 @@ pub enum ChannelType { }, DirectTcpip(TcpChannelInfo), ForwardedTcpIp(TcpChannelInfo), + ForwardedStreamLocal(StreamLocalChannelInfo), AgentForward, Unknown { typ: Vec, @@ -107,6 +108,12 @@ pub struct TcpChannelInfo { pub originator_port: u32, } +#[derive(Debug)] +pub struct StreamLocalChannelInfo { + pub client_socket_path: String, + pub server_socket_path: String, +} + impl TcpChannelInfo { fn new(r: &mut Position) -> Result { let host_to_connect = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index c82ad83f..d88ff392 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1026,6 +1026,14 @@ impl Session { } Ok(()) } + b"streamlocal-forward" => { + // NEED HELP + Ok(()) + } + b"cancel-streamlocal-forward" => { + // NEED HELP + Ok(()) + } _ => { if let Some(ref mut enc) = self.common.encrypted { push_packet!(enc.write, { @@ -1090,6 +1098,13 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(true); } + Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { + // NEED HELP: how to do this? + let _ = return_channel.send(None); + } + Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { + let _ = return_channel.send(true); + } None => { error!("Received global request failure for unknown request!") } @@ -1108,6 +1123,12 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(false); } + Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { + let _ = return_channel.send(None); + } + Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { + let _ = return_channel.send(false); + } None => { error!("Received global request failure for unknown request!") } @@ -1214,6 +1235,21 @@ impl Session { } result } + ChannelType::ForwardedStreamLocal(d) => { + let mut result = handler + .channel_open_forwarded_streamlocal( + channel, + &d.server_socket_path, + &d.client_socket_path, + self, + ) + .await; + if let Ok(allowed) = &mut result { + self.channels.insert(sender_channel, reference); + self.finalize_channel_open(&msg, channel_params, *allowed); + } + result + } ChannelType::AgentForward => { if let Some(ref mut enc) = self.common.encrypted { msg.fail( diff --git a/russh/src/server/mod.rs b/russh/src/server/mod.rs index bc10d00c..3f722053 100644 --- a/russh/src/server/mod.rs +++ b/russh/src/server/mod.rs @@ -324,6 +324,17 @@ pub trait Handler: Sized { Ok(false) } + #[allow(unused_variables)] + async fn channel_open_forwarded_streamlocal( + &mut self, + channel: Channel, + server_socket_path: &str, + client_socket_path: &str, + session: &mut Session, + ) -> Result { + Ok(false) + } + /// Called when the client confirmed our request to open a /// channel. A channel can only be written to after receiving this /// message (this library panics otherwise). @@ -523,6 +534,26 @@ pub trait Handler: Sized { ) -> Result { Ok(false) } + + #[allow(unused_variables)] + async fn streamlocal_forward( + &mut self, + server_socket_path: &str, + client_socket_path: &str, + session: &mut Session, + ) -> Result { + Ok(false) + } + + #[allow(unused_variables)] + async fn cancel_streamlocal_forward( + &mut self, + server_socket_path: &str, + client_socket_path: &str, + session: &mut Session, + ) -> Result { + Ok(false) + } } #[async_trait] diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index 02fd4638..0ad696e2 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -59,6 +59,16 @@ pub enum Msg { address: String, port: u32, }, + StreamLocalForward { + // Provide a channel for the reply result to request a reply from the server + reply_channel: Option>>, + socket_path: String, + }, + CancelStreamLocalForward { + // Provide a channel for the reply result to request a reply from the server + reply_channel: Option>, + socket_path: String, + }, Disconnect { reason: crate::Disconnect, description: String, @@ -180,6 +190,27 @@ impl Handle { } } + // Notifies the client that it can open UDS forwarding channels for a given UDS + pub async fn forward_streamlocal(&self, socket_path: String) -> Result { + let (reply_send, reply_recv) = oneshot::channel(); + self.sender + .send(Msg::StreamLocalForward { + reply_channel: Some(reply_send), + socket_path, + }) + .await + .map_err(|_| ())?; + + match reply_recv.await { + Ok(Some(socket_path)) => Ok(socket_path), + Ok(None) => Err(()), + Err(e) => { + error!("Unable to receive StreamLocalForward result: {e:?}"); + Err(()) + } + } + } + /// Notifies the client that it can no longer open TCP/IP forwarding channel for a port. pub async fn cancel_forward_tcpip(&self, address: String, port: u32) -> Result<(), ()> { let (reply_send, reply_recv) = oneshot::channel(); @@ -533,6 +564,12 @@ impl Session { Some(Msg::CancelTcpIpForward { address, port, reply_channel }) => { self.cancel_tcpip_forward(&address, port, reply_channel); } + Some(Msg::StreamLocalForward { socket_path, reply_channel }) => { + self.streamlocal_forward(&socket_path, reply_channel); + } + Some(Msg::CancelStreamLocalForward { socket_path, reply_channel }) => { + self.cancel_streamlocal_forward(&socket_path, reply_channel); + } Some(Msg::Disconnect {reason, description, language_tag}) => { self.common.disconnect(reason, &description, &language_tag); } @@ -1028,6 +1065,48 @@ impl Session { } } + pub fn streamlocal_forward( + &mut self, + socket_path: &str, + reply_channel: Option>>, + ) { + if let Some(ref mut enc) = self.common.encrypted { + let want_reply = reply_channel.is_some(); + if let Some(reply_channel) = reply_channel { + self.open_global_requests.push_back( + crate::session::GlobalRequestResponse::StreamLocalForward(reply_channel), + ); + } + push_packet!(enc.write, { + enc.write.push(msg::GLOBAL_REQUEST); + enc.write.extend_ssh_string(b"streamlocal-forward"); + enc.write.push(want_reply as u8); + enc.write.extend_ssh_string(socket_path.as_bytes()); + }) + } + } + + pub fn cancel_streamlocal_forward( + &mut self, + socket_path: &str, + reply_channel: Option>, + ) { + if let Some(ref mut enc) = self.common.encrypted { + let want_reply = reply_channel.is_some(); + if let Some(reply_channel) = reply_channel { + self.open_global_requests.push_back( + crate::session::GlobalRequestResponse::CancelStreamLocalForward(reply_channel), + ); + } + push_packet!(enc.write, { + enc.write.push(msg::GLOBAL_REQUEST); + enc.write.extend_ssh_string(b"cancel-streamlocal-forward"); + enc.write.push(want_reply as u8); + enc.write.extend_ssh_string(socket_path.as_bytes()); + }); + } + } + /// Returns the SSH ID (Protocol Version + Software Version) the client sent when connecting /// /// This should contain only ASCII characters for implementations conforming to RFC4253, Section 4.2: diff --git a/russh/src/session.rs b/russh/src/session.rs index c1958227..fdcddc22 100644 --- a/russh/src/session.rs +++ b/russh/src/session.rs @@ -625,4 +625,6 @@ pub(crate) enum GlobalRequestResponse { TcpIpForward(oneshot::Sender>), /// request was for CancelTcpIpForward, sends true for success or false for failure CancelTcpIpForward(oneshot::Sender), + StreamLocalForward(oneshot::Sender>), + CancelStreamLocalForward(oneshot::Sender), } From dc2572495d6d2f2991368638da9c344b6c9fcd00 Mon Sep 17 00:00:00 2001 From: kanpov Date: Sat, 6 Jul 2024 12:22:25 +0300 Subject: [PATCH 2/9] Implement more missing packet behavior --- russh/src/client/encrypted.rs | 15 ++++++++++-- russh/src/client/mod.rs | 4 +-- russh/src/parsing.rs | 20 +++++++++++++++ russh/src/server/encrypted.rs | 46 ++++++++++++++++++++++++++++++++--- russh/src/server/mod.rs | 5 ++-- 5 files changed, 79 insertions(+), 11 deletions(-) diff --git a/russh/src/client/encrypted.rs b/russh/src/client/encrypted.rs index 44229f7c..e49b24c9 100644 --- a/russh/src/client/encrypted.rs +++ b/russh/src/client/encrypted.rs @@ -862,8 +862,19 @@ impl Session { let _ = return_channel.send(true); } Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - // NEED HELP: how to do this? - let _ = return_channel.send(None); + let mut r = buf.reader(1); + let socket_path: Option = match r.read_string() { + Ok(socket_path) => Some( + std::str::from_utf8(socket_path) + .map_err(crate::Error::from)? + .into(), + ), + Err(e) => { + error!("Error parsing socket path for StreamLocalForward request: {e:?}"); + None + } + }; + let _ = return_channel.send(socket_path); } Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { let _ = return_channel.send(true); diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index d0a4bde0..201dc5d7 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -1557,8 +1557,8 @@ pub trait Handler: Sized + Send { async fn server_channel_open_forwarded_streamlocal( &mut self, channel: Channel, - remote_socket_path: &str, - local_socket_path: &str, + server_socket_path: &str, + client_socket_path: &str, session: &mut Session, ) -> Result<(), Self::Error> { Ok(()) diff --git a/russh/src/parsing.rs b/russh/src/parsing.rs index 04e07ba1..e2c7ed40 100644 --- a/russh/src/parsing.rs +++ b/russh/src/parsing.rs @@ -34,6 +34,9 @@ impl OpenChannelMessage { } b"direct-tcpip" => ChannelType::DirectTcpip(TcpChannelInfo::new(r)?), b"forwarded-tcpip" => ChannelType::ForwardedTcpIp(TcpChannelInfo::new(r)?), + b"forwarded-streamlocal" => { + ChannelType::ForwardedStreamLocal(StreamLocalChannelInfo::new(r)?) + } b"auth-agent@openssh.com" => ChannelType::AgentForward, t => ChannelType::Unknown { typ: t.to_vec() }, }; @@ -114,6 +117,23 @@ pub struct StreamLocalChannelInfo { pub server_socket_path: String, } +impl StreamLocalChannelInfo { + fn new(r: &mut Position) -> Result { + // NEED HELP: is this completely correct? + let client_socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) + .map_err(crate::Error::from)? + .to_owned(); + let server_socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) + .map_err(crate::Error::from)? + .to_owned(); + + Ok(Self { + client_socket_path, + server_socket_path, + }) + } +} + impl TcpChannelInfo { fn new(r: &mut Position) -> Result { let host_to_connect = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index d88ff392..75a9cbbb 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1027,11 +1027,38 @@ impl Session { Ok(()) } b"streamlocal-forward" => { - // NEED HELP + let server_socket_path = + std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) + .map_err(crate::Error::from)?; + debug!("handler.streamlocal_forward {:?}", server_socket_path); + let mut client_socket_path = String::from(server_socket_path).clone(); + let result = handler + .streamlocal_forward(server_socket_path, &mut client_socket_path, self) + .await?; + if let Some(ref mut enc) = self.common.encrypted { + if result { + push_packet!(enc.write, enc.write.push(msg::REQUEST_SUCCESS)) + } else { + push_packet!(enc.write, enc.write.push(msg::REQUEST_FAILURE)) + } + } Ok(()) } b"cancel-streamlocal-forward" => { - // NEED HELP + let socket_path = + std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) + .map_err(crate::Error::from)?; + debug!("handler.cancel_streamlocal_forward {:?}", socket_path); + let result = handler + .cancel_streamlocal_forward(socket_path, self) + .await?; + if let Some(ref mut enc) = self.common.encrypted { + if result { + push_packet!(enc.write, enc.write.push(msg::REQUEST_SUCCESS)) + } else { + push_packet!(enc.write, enc.write.push(msg::REQUEST_FAILURE)) + } + } Ok(()) } _ => { @@ -1099,8 +1126,19 @@ impl Session { let _ = return_channel.send(true); } Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - // NEED HELP: how to do this? - let _ = return_channel.send(None); + let mut r = buf.reader(1); + let socket_path: Option = match r.read_string() { + Ok(socket_path) => Some( + std::str::from_utf8(socket_path) + .map_err(crate::Error::from)? + .into(), + ), + Err(e) => { + error!("Error parsing socket path for StreamLocalForward request: {e:?}"); + None + } + }; + let _ = return_channel.send(socket_path); } Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { let _ = return_channel.send(true); diff --git a/russh/src/server/mod.rs b/russh/src/server/mod.rs index 3f722053..28be7dcf 100644 --- a/russh/src/server/mod.rs +++ b/russh/src/server/mod.rs @@ -539,7 +539,7 @@ pub trait Handler: Sized { async fn streamlocal_forward( &mut self, server_socket_path: &str, - client_socket_path: &str, + client_socket_path: &mut str, session: &mut Session, ) -> Result { Ok(false) @@ -548,8 +548,7 @@ pub trait Handler: Sized { #[allow(unused_variables)] async fn cancel_streamlocal_forward( &mut self, - server_socket_path: &str, - client_socket_path: &str, + socket_path: &str, session: &mut Session, ) -> Result { Ok(false) From 7ff13764cc4dc5b187e012c6ea4bcf43f935f9d9 Mon Sep 17 00:00:00 2001 From: kanpov Date: Sat, 6 Jul 2024 12:41:07 +0300 Subject: [PATCH 3/9] Implement missing required client-side code for forwarding, add more docs --- README.md | 1 + russh/src/client/mod.rs | 68 +++++++++++++++++++++++++++++++++++++ russh/src/client/session.rs | 10 +++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 921c67d5..a1fa36c6 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti * `direct-tcpip` (local port forwarding) * `forward-tcpip` (remote port forwarding) ✨ * `direct-streamlocal` (local UNIX socket forwarding, client only) ✨ +* `forward-streamlocal` (remote UNIX socket forwarding) ✨ * Ciphers: * `chacha20-poly1305@openssh.com` * `aes256-gcm@openssh.com` ✨ diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index 201dc5d7..03dbdadc 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -162,6 +162,16 @@ pub enum Msg { address: String, port: u32, }, + StreamLocalForward { + /// Provide a channel for the reply result to request a reply from the server + reply_channel: Option>>, + socket_path: String, + }, + CancelStreamLocalForward { + /// Provide a channel for the reply result to request a reply from the server + reply_channel: Option>, + socket_path: String, + }, Close { id: ChannelId, }, @@ -573,6 +583,7 @@ impl Handle { } } + // Requests the server to close a TCP/IP forward channel pub async fn cancel_tcpip_forward>( &self, address: A, @@ -598,6 +609,54 @@ impl Handle { } } + // Requests the server to open a UDS forward channel + pub async fn streamlocal_forward>( + &mut self, + socket_path: A, + ) -> Result { + let (reply_send, reply_recv) = oneshot::channel(); + self.sender + .send(Msg::StreamLocalForward { + reply_channel: Some(reply_send), + socket_path: socket_path.into(), + }) + .await + .map_err(|_| crate::Error::SendError)?; + + match reply_recv.await { + Ok(Some(returned_socket_path)) => Ok(returned_socket_path), + Ok(None) => Err(crate::Error::RequestDenied), + Err(e) => { + error!("Unable to receive StreamLocalForward result: {e:?}"); + Err(crate::Error::Disconnect) + } + } + } + + // Requests the server to close a UDS forward channel + pub async fn cancel_streamlocal_forward>( + &self, + socket_path: A, + ) -> Result<(), crate::Error> { + let (reply_send, reply_recv) = oneshot::channel(); + self.sender + .send(Msg::CancelStreamLocalForward { + reply_channel: Some(reply_send), + socket_path: socket_path.into(), + }) + .await + .map_err(|_| crate::Error::SendError)?; + + match reply_recv.await { + Ok(true) => Ok(()), + Ok(false) => Err(crate::Error::RequestDenied), + Err(e) => { + error!("Unable to receive CancelStreamLocalForward result: {e:?}"); + Err(crate::Error::Disconnect) + } + } + } + /// Sends a disconnect message. pub async fn disconnect( &self, @@ -1052,6 +1111,14 @@ impl Session { address, port, } => self.cancel_tcpip_forward(reply_channel, &address, port), + Msg::StreamLocalForward { + reply_channel, + socket_path, + } => self.streamlocal_forward(reply_channel, &socket_path), + Msg::CancelStreamLocalForward { + reply_channel, + socket_path, + } => self.cancel_streamlocal_forward(reply_channel, &socket_path), Msg::Disconnect { reason, description, @@ -1553,6 +1620,7 @@ pub trait Handler: Sized + Send { Ok(()) } + // Called when the server opens a channel for a new remote UDS forwarding connection #[allow(unused_variables)] async fn server_channel_open_forwarded_streamlocal( &mut self, diff --git a/russh/src/client/session.rs b/russh/src/client/session.rs index 83dc9a12..3f9f8053 100644 --- a/russh/src/client/session.rs +++ b/russh/src/client/session.rs @@ -294,7 +294,7 @@ impl Session { /// Requests cancellation of TCP/IP forwarding from the server /// - /// If `want_reply` is `true`, returns a oneshot receiveing the server's reply: + /// If `want_reply` is `true`, returns a oneshot receiving the server's reply: /// `true` for a success message, or `false` for failure pub fn cancel_tcpip_forward( &mut self, @@ -319,6 +319,10 @@ impl Session { } } + /// Requests a UDS forwarding from the server, `socket path` being the server side socket path. + /// + /// If `reply_channel` is not None, sets want_reply and returns the server's response via the channel, + /// [`Some`] for a success message with the client side socket path, [`None`] for failure. pub fn streamlocal_forward( &mut self, reply_channel: Option>>, @@ -340,6 +344,10 @@ impl Session { } } + /// Requests cancellation of UDS forwarding from the server + /// + /// If `want_reply` is true, returns a oneshot receiving the server's reply: + /// `true` for a success message and `false` for failure. pub fn cancel_streamlocal_forward( &mut self, reply_channel: Option>, From db5fc40b304a5352896a8d8ea1381a8742abf05c Mon Sep 17 00:00:00 2001 From: kanpov Date: Sat, 6 Jul 2024 12:59:09 +0300 Subject: [PATCH 4/9] Implement channel_open_forwarded_streamlocal --- russh/src/server/session.rs | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index 0ad696e2..0adcec76 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -42,6 +42,11 @@ pub enum Msg { originator_port: u32, channel_ref: ChannelRef, }, + ChannelOpenForwardedStreamLocal { + server_socket_path: String, + client_socket_path: String, + channel_ref: ChannelRef, + }, ChannelOpenX11 { originator_address: String, originator_port: u32, @@ -306,6 +311,27 @@ impl Handle { .await } + pub async fn channel_open_forwarded_streamlocal, B: Into>( + &self, + server_socket_path: A, + client_socket_path: B, + ) -> Result, Error> { + let (sender, receiver) = unbounded_channel(); + let channel_ref = ChannelRef::new(sender); + let window_size_ref = channel_ref.window_size().clone(); + + self.sender + .send(Msg::ChannelOpenForwardedStreamLocal { + server_socket_path: server_socket_path.into(), + client_socket_path: client_socket_path.into(), + channel_ref, + }) + .await + .map_err(|_| Error::SendError)?; + self.wait_channel_confirmation(receiver, window_size_ref) + .await + } + pub async fn channel_open_x11>( &self, originator_address: A, @@ -554,6 +580,10 @@ impl Session { let id = self.channel_open_forwarded_tcpip(&connected_address, connected_port, &originator_address, originator_port)?; self.channels.insert(id, channel_ref); } + Some(Msg::ChannelOpenForwardedStreamLocal { server_socket_path, client_socket_path, channel_ref }) => { + let id = self.channel_open_forwarded_streamlocal(&server_socket_path, &client_socket_path)?; + self.channels.insert(id, channel_ref); + } Some(Msg::ChannelOpenX11 { originator_address, originator_port, channel_ref }) => { let id = self.channel_open_x11(&originator_address, originator_port)?; self.channels.insert(id, channel_ref); @@ -956,6 +986,18 @@ impl Session { }) } + pub fn channel_open_forwarded_streamlocal( + &mut self, + server_socket_path: &str, + client_socket_path: &str, + ) -> Result { + self.channel_open_generic(b"forwarded-streamlocal", |write| { + // NEED HELP: is this correct? + write.extend_ssh_string(server_socket_path.as_bytes()); + write.extend_ssh_string(client_socket_path.as_bytes()); + }) + } + /// Open a new X11 channel, when a connection comes to a /// local port. See [RFC4254](https://tools.ietf.org/html/rfc4254#section-6.3.2). /// TCP/IP packets can then be tunneled through the channel using `.data()`. From 44f59df8d5f0f8d0a5c5ec55b15fd24a4a43186c Mon Sep 17 00:00:00 2001 From: kanpov Date: Tue, 9 Jul 2024 10:47:56 +0300 Subject: [PATCH 5/9] Resolve missing namespacing --- russh/src/client/session.rs | 6 ++++-- russh/src/server/encrypted.rs | 4 ++-- russh/src/server/session.rs | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/russh/src/client/session.rs b/russh/src/client/session.rs index 3f9f8053..309bf8bc 100644 --- a/russh/src/client/session.rs +++ b/russh/src/client/session.rs @@ -337,7 +337,8 @@ impl Session { } push_packet!(enc.write, { enc.write.push(msg::GLOBAL_REQUEST); - enc.write.extend_ssh_string(b"streamlocal-forward"); + enc.write + .extend_ssh_string(b"streamlocal-forward@openssh.com"); enc.write.push(want_reply as u8); enc.write.extend_ssh_string(socket_path.as_bytes()); }); @@ -362,7 +363,8 @@ impl Session { } push_packet!(enc.write, { enc.write.push(msg::GLOBAL_REQUEST); - enc.write.extend_ssh_string(b"cancel-streamlocal-forward"); + enc.write + .extend_ssh_string(b"cancel-streamlocal-forward@openssh.com"); enc.write.push(want_reply as u8); enc.write.extend_ssh_string(socket_path.as_bytes()); }); diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index 75a9cbbb..26225334 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1026,7 +1026,7 @@ impl Session { } Ok(()) } - b"streamlocal-forward" => { + b"streamlocal-forward@openssh.com" => { let server_socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) .map_err(crate::Error::from)?; @@ -1044,7 +1044,7 @@ impl Session { } Ok(()) } - b"cancel-streamlocal-forward" => { + b"cancel-streamlocal-forward@openssh.com" => { let socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) .map_err(crate::Error::from)?; diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index 0adcec76..0b5d37f6 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -1121,7 +1121,8 @@ impl Session { } push_packet!(enc.write, { enc.write.push(msg::GLOBAL_REQUEST); - enc.write.extend_ssh_string(b"streamlocal-forward"); + enc.write + .extend_ssh_string(b"streamlocal-forward@openssh.com"); enc.write.push(want_reply as u8); enc.write.extend_ssh_string(socket_path.as_bytes()); }) @@ -1142,7 +1143,8 @@ impl Session { } push_packet!(enc.write, { enc.write.push(msg::GLOBAL_REQUEST); - enc.write.extend_ssh_string(b"cancel-streamlocal-forward"); + enc.write + .extend_ssh_string(b"cancel-streamlocal-forward@openssh.com"); enc.write.push(want_reply as u8); enc.write.extend_ssh_string(socket_path.as_bytes()); }); From a66f057f69c8e45b024f3cc6d0e18475294b3323 Mon Sep 17 00:00:00 2001 From: kanpov Date: Tue, 9 Jul 2024 10:52:03 +0300 Subject: [PATCH 6/9] Use reserved field --- russh/src/server/session.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index 0b5d37f6..b27acb53 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -580,8 +580,8 @@ impl Session { let id = self.channel_open_forwarded_tcpip(&connected_address, connected_port, &originator_address, originator_port)?; self.channels.insert(id, channel_ref); } - Some(Msg::ChannelOpenForwardedStreamLocal { server_socket_path, client_socket_path, channel_ref }) => { - let id = self.channel_open_forwarded_streamlocal(&server_socket_path, &client_socket_path)?; + Some(Msg::ChannelOpenForwardedStreamLocal { server_socket_path, client_socket_path: _, channel_ref }) => { + let id = self.channel_open_forwarded_streamlocal(&server_socket_path)?; self.channels.insert(id, channel_ref); } Some(Msg::ChannelOpenX11 { originator_address, originator_port, channel_ref }) => { @@ -988,13 +988,11 @@ impl Session { pub fn channel_open_forwarded_streamlocal( &mut self, - server_socket_path: &str, client_socket_path: &str, ) -> Result { self.channel_open_generic(b"forwarded-streamlocal", |write| { - // NEED HELP: is this correct? - write.extend_ssh_string(server_socket_path.as_bytes()); write.extend_ssh_string(client_socket_path.as_bytes()); + write.extend_ssh_string(b""); }) } From 69da16092e2f628fd0628de0b865712dd895b394 Mon Sep 17 00:00:00 2001 From: kanpov Date: Tue, 9 Jul 2024 11:04:24 +0300 Subject: [PATCH 7/9] Finish reserved path fixes --- russh/src/client/encrypted.rs | 3 +-- russh/src/client/mod.rs | 3 +-- russh/src/parsing.rs | 14 +++----------- russh/src/server/encrypted.rs | 7 +------ russh/src/server/mod.rs | 3 +-- 5 files changed, 7 insertions(+), 23 deletions(-) diff --git a/russh/src/client/encrypted.rs b/russh/src/client/encrypted.rs index e49b24c9..5b45d941 100644 --- a/russh/src/client/encrypted.rs +++ b/russh/src/client/encrypted.rs @@ -812,8 +812,7 @@ impl Session { client .server_channel_open_forwarded_streamlocal( channel, - &d.server_socket_path, - &d.client_socket_path, + &d.socket_path, self, ) .await?; diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index 03dbdadc..a47f0c77 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -1625,8 +1625,7 @@ pub trait Handler: Sized + Send { async fn server_channel_open_forwarded_streamlocal( &mut self, channel: Channel, - server_socket_path: &str, - client_socket_path: &str, + socket_path: &str, session: &mut Session, ) -> Result<(), Self::Error> { Ok(()) diff --git a/russh/src/parsing.rs b/russh/src/parsing.rs index e2c7ed40..21da9ae7 100644 --- a/russh/src/parsing.rs +++ b/russh/src/parsing.rs @@ -113,24 +113,16 @@ pub struct TcpChannelInfo { #[derive(Debug)] pub struct StreamLocalChannelInfo { - pub client_socket_path: String, - pub server_socket_path: String, + pub socket_path: String, } impl StreamLocalChannelInfo { fn new(r: &mut Position) -> Result { - // NEED HELP: is this completely correct? - let client_socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) - .map_err(crate::Error::from)? - .to_owned(); - let server_socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) + let socket_path = std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) .map_err(crate::Error::from)? .to_owned(); - Ok(Self { - client_socket_path, - server_socket_path, - }) + Ok(Self { socket_path }) } } diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index 26225334..5d528aff 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1275,12 +1275,7 @@ impl Session { } ChannelType::ForwardedStreamLocal(d) => { let mut result = handler - .channel_open_forwarded_streamlocal( - channel, - &d.server_socket_path, - &d.client_socket_path, - self, - ) + .channel_open_forwarded_streamlocal(channel, &d.socket_path, self) .await; if let Ok(allowed) = &mut result { self.channels.insert(sender_channel, reference); diff --git a/russh/src/server/mod.rs b/russh/src/server/mod.rs index 28be7dcf..7791b40e 100644 --- a/russh/src/server/mod.rs +++ b/russh/src/server/mod.rs @@ -328,8 +328,7 @@ pub trait Handler: Sized { async fn channel_open_forwarded_streamlocal( &mut self, channel: Channel, - server_socket_path: &str, - client_socket_path: &str, + socket_path: &str, session: &mut Session, ) -> Result { Ok(false) From 89d26002e791df95f4009ec3fe267ac002cbad5d Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 4 Aug 2024 10:39:32 +0200 Subject: [PATCH 8/9] fixes & cleanup --- russh/src/client/encrypted.rs | 16 +----- russh/src/client/mod.rs | 8 +-- russh/src/client/session.rs | 8 +-- russh/src/parsing.rs | 2 +- russh/src/server/encrypted.rs | 28 +--------- russh/src/server/session.rs | 102 ---------------------------------- russh/src/session.rs | 3 +- 7 files changed, 15 insertions(+), 152 deletions(-) diff --git a/russh/src/client/encrypted.rs b/russh/src/client/encrypted.rs index 20de6a43..ea8b782e 100644 --- a/russh/src/client/encrypted.rs +++ b/russh/src/client/encrypted.rs @@ -860,19 +860,7 @@ impl Session { let _ = return_channel.send(true); } Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - let mut r = buf.reader(1); - let socket_path: Option = match r.read_string() { - Ok(socket_path) => Some( - std::str::from_utf8(socket_path) - .map_err(crate::Error::from)? - .into(), - ), - Err(e) => { - error!("Error parsing socket path for StreamLocalForward request: {e:?}"); - None - } - }; - let _ = return_channel.send(socket_path); + let _ = return_channel.send(true); } Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { let _ = return_channel.send(true); @@ -896,7 +884,7 @@ impl Session { let _ = return_channel.send(false); } Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - let _ = return_channel.send(None); + let _ = return_channel.send(false); } Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { let _ = return_channel.send(false); diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index 09be2652..447ca041 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -162,7 +162,7 @@ pub enum Msg { }, StreamLocalForward { /// Provide a channel for the reply result to request a reply from the server - reply_channel: Option>>, + reply_channel: Option>, socket_path: String, }, CancelStreamLocalForward { @@ -611,7 +611,7 @@ impl Handle { pub async fn streamlocal_forward>( &mut self, socket_path: A, - ) -> Result { + ) -> Result<(), crate::Error> { let (reply_send, reply_recv) = oneshot::channel(); self.sender .send(Msg::StreamLocalForward { @@ -622,8 +622,8 @@ impl Handle { .map_err(|_| crate::Error::SendError)?; match reply_recv.await { - Ok(Some(returned_socket_path)) => Ok(returned_socket_path), - Ok(None) => Err(crate::Error::RequestDenied), + Ok(true) => Ok(()), + Ok(false) => Err(crate::Error::RequestDenied), Err(e) => { error!("Unable to receive StreamLocalForward result: {e:?}"); Err(crate::Error::Disconnect) diff --git a/russh/src/client/session.rs b/russh/src/client/session.rs index 12da6ab0..26f8a761 100644 --- a/russh/src/client/session.rs +++ b/russh/src/client/session.rs @@ -293,7 +293,7 @@ impl Session { /// Requests cancellation of TCP/IP forwarding from the server /// - /// If `want_reply` is `true`, returns a oneshot receiving the server's reply: + /// If `reply_channel` is not None, sets want_reply and returns the server's response via the channel, /// `true` for a success message, or `false` for failure pub fn cancel_tcpip_forward( &mut self, @@ -321,10 +321,10 @@ impl Session { /// Requests a UDS forwarding from the server, `socket path` being the server side socket path. /// /// If `reply_channel` is not None, sets want_reply and returns the server's response via the channel, - /// [`Some`] for a success message with the client side socket path, [`None`] for failure. + /// `true` for a success message, or `false` for failure pub fn streamlocal_forward( &mut self, - reply_channel: Option>>, + reply_channel: Option>, socket_path: &str, ) { if let Some(ref mut enc) = self.common.encrypted { @@ -346,7 +346,7 @@ impl Session { /// Requests cancellation of UDS forwarding from the server /// - /// If `want_reply` is true, returns a oneshot receiving the server's reply: + /// If `reply_channel` is not None, sets want_reply and returns the server's response via the channel, /// `true` for a success message and `false` for failure. pub fn cancel_streamlocal_forward( &mut self, diff --git a/russh/src/parsing.rs b/russh/src/parsing.rs index 1ea32560..fe80c974 100644 --- a/russh/src/parsing.rs +++ b/russh/src/parsing.rs @@ -32,7 +32,7 @@ impl OpenChannelMessage { } b"direct-tcpip" => ChannelType::DirectTcpip(TcpChannelInfo::new(r)?), b"forwarded-tcpip" => ChannelType::ForwardedTcpIp(TcpChannelInfo::new(r)?), - b"forwarded-streamlocal" => { + b"forwarded-streamlocal@openssh.com" => { ChannelType::ForwardedStreamLocal(StreamLocalChannelInfo::new(r)?) } b"auth-agent@openssh.com" => ChannelType::AgentForward, diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index d1e147d7..70b47e5e 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1122,25 +1122,7 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(true); } - Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - let mut r = buf.reader(1); - let socket_path: Option = match r.read_string() { - Ok(socket_path) => Some( - std::str::from_utf8(socket_path) - .map_err(crate::Error::from)? - .into(), - ), - Err(e) => { - error!("Error parsing socket path for StreamLocalForward request: {e:?}"); - None - } - }; - let _ = return_channel.send(socket_path); - } - Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { - let _ = return_channel.send(true); - } - None => { + _ => { error!("Received global request failure for unknown request!") } } @@ -1158,13 +1140,7 @@ impl Session { Some(GlobalRequestResponse::CancelTcpIpForward(return_channel)) => { let _ = return_channel.send(false); } - Some(GlobalRequestResponse::StreamLocalForward(return_channel)) => { - let _ = return_channel.send(None); - } - Some(GlobalRequestResponse::CancelStreamLocalForward(return_channel)) => { - let _ = return_channel.send(false); - } - None => { + _ => { error!("Received global request failure for unknown request!") } } diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index de6f2269..45d22459 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -64,16 +64,6 @@ pub enum Msg { address: String, port: u32, }, - StreamLocalForward { - // Provide a channel for the reply result to request a reply from the server - reply_channel: Option>>, - socket_path: String, - }, - CancelStreamLocalForward { - // Provide a channel for the reply result to request a reply from the server - reply_channel: Option>, - socket_path: String, - }, Disconnect { reason: crate::Disconnect, description: String, @@ -195,48 +185,6 @@ impl Handle { } } - // Notifies the client that it can open UDS forwarding channels for a given UDS - pub async fn forward_streamlocal(&self, socket_path: String) -> Result { - let (reply_send, reply_recv) = oneshot::channel(); - self.sender - .send(Msg::StreamLocalForward { - reply_channel: Some(reply_send), - socket_path, - }) - .await - .map_err(|_| ())?; - - match reply_recv.await { - Ok(Some(socket_path)) => Ok(socket_path), - Ok(None) => Err(()), - Err(e) => { - error!("Unable to receive StreamLocalForward result: {e:?}"); - Err(()) - } - } - } - - /// Notifies the client that it can no longer open TCP/IP forwarding channel for a port. - pub async fn cancel_forward_tcpip(&self, address: String, port: u32) -> Result<(), ()> { - let (reply_send, reply_recv) = oneshot::channel(); - self.sender - .send(Msg::CancelTcpIpForward { - reply_channel: Some(reply_send), - address, - port, - }) - .await - .map_err(|_| ())?; - match reply_recv.await { - Ok(true) => Ok(()), - Ok(false) => Err(()), // crate::Error::RequestDenied - Err(e) => { - error!("Unable to receive CancelTcpIpForward result: {e:?}"); - Err(()) // crate::Error::Disconnect - } - } - } - /// Request a session channel (the most basic type of /// channel). This function returns `Ok(..)` immediately if the /// connection is authenticated, but the channel only becomes @@ -594,12 +542,6 @@ impl Session { Some(Msg::CancelTcpIpForward { address, port, reply_channel }) => { self.cancel_tcpip_forward(&address, port, reply_channel); } - Some(Msg::StreamLocalForward { socket_path, reply_channel }) => { - self.streamlocal_forward(&socket_path, reply_channel); - } - Some(Msg::CancelStreamLocalForward { socket_path, reply_channel }) => { - self.cancel_streamlocal_forward(&socket_path, reply_channel); - } Some(Msg::Disconnect {reason, description, language_tag}) => { self.common.disconnect(reason, &description, &language_tag); } @@ -1105,50 +1047,6 @@ impl Session { } } - pub fn streamlocal_forward( - &mut self, - socket_path: &str, - reply_channel: Option>>, - ) { - if let Some(ref mut enc) = self.common.encrypted { - let want_reply = reply_channel.is_some(); - if let Some(reply_channel) = reply_channel { - self.open_global_requests.push_back( - crate::session::GlobalRequestResponse::StreamLocalForward(reply_channel), - ); - } - push_packet!(enc.write, { - enc.write.push(msg::GLOBAL_REQUEST); - enc.write - .extend_ssh_string(b"streamlocal-forward@openssh.com"); - enc.write.push(want_reply as u8); - enc.write.extend_ssh_string(socket_path.as_bytes()); - }) - } - } - - pub fn cancel_streamlocal_forward( - &mut self, - socket_path: &str, - reply_channel: Option>, - ) { - if let Some(ref mut enc) = self.common.encrypted { - let want_reply = reply_channel.is_some(); - if let Some(reply_channel) = reply_channel { - self.open_global_requests.push_back( - crate::session::GlobalRequestResponse::CancelStreamLocalForward(reply_channel), - ); - } - push_packet!(enc.write, { - enc.write.push(msg::GLOBAL_REQUEST); - enc.write - .extend_ssh_string(b"cancel-streamlocal-forward@openssh.com"); - enc.write.push(want_reply as u8); - enc.write.extend_ssh_string(socket_path.as_bytes()); - }); - } - } - /// Returns the SSH ID (Protocol Version + Software Version) the client sent when connecting /// /// This should contain only ASCII characters for implementations conforming to RFC4253, Section 4.2: diff --git a/russh/src/session.rs b/russh/src/session.rs index 78f20dac..0a1f633b 100644 --- a/russh/src/session.rs +++ b/russh/src/session.rs @@ -626,6 +626,7 @@ pub(crate) enum GlobalRequestResponse { TcpIpForward(oneshot::Sender>), /// request was for CancelTcpIpForward, sends true for success or false for failure CancelTcpIpForward(oneshot::Sender), - StreamLocalForward(oneshot::Sender>), + /// request was for StreamLocalForward, sends true for success or false for failure + StreamLocalForward(oneshot::Sender), CancelStreamLocalForward(oneshot::Sender), } From 5bc1378ed63d42c88275f8d6ef08d1273d70da8b Mon Sep 17 00:00:00 2001 From: Eugene Date: Sun, 4 Aug 2024 10:55:30 +0200 Subject: [PATCH 9/9] more fixes --- russh/src/server/encrypted.rs | 19 +++++++++---------- russh/src/server/mod.rs | 13 +------------ russh/src/server/session.rs | 34 ++++++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/russh/src/server/encrypted.rs b/russh/src/server/encrypted.rs index 70b47e5e..9f790610 100644 --- a/russh/src/server/encrypted.rs +++ b/russh/src/server/encrypted.rs @@ -1028,9 +1028,8 @@ impl Session { std::str::from_utf8(r.read_string().map_err(crate::Error::from)?) .map_err(crate::Error::from)?; debug!("handler.streamlocal_forward {:?}", server_socket_path); - let mut client_socket_path = String::from(server_socket_path).clone(); let result = handler - .streamlocal_forward(server_socket_path, &mut client_socket_path, self) + .streamlocal_forward(server_socket_path, self) .await?; if let Some(ref mut enc) = self.common.encrypted { if result { @@ -1246,15 +1245,15 @@ impl Session { } result } - ChannelType::ForwardedStreamLocal(d) => { - let mut result = handler - .channel_open_forwarded_streamlocal(channel, &d.socket_path, self) - .await; - if let Ok(allowed) = &mut result { - self.channels.insert(sender_channel, reference); - self.finalize_channel_open(&msg, channel_params, *allowed); + ChannelType::ForwardedStreamLocal(_) => { + if let Some(ref mut enc) = self.common.encrypted { + msg.fail( + &mut enc.write, + msg::SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, + b"Unsupported channel type", + ); } - result + Ok(false) } ChannelType::AgentForward => { if let Some(ref mut enc) = self.common.encrypted { diff --git a/russh/src/server/mod.rs b/russh/src/server/mod.rs index 80c16236..c715dbbd 100644 --- a/russh/src/server/mod.rs +++ b/russh/src/server/mod.rs @@ -324,16 +324,6 @@ pub trait Handler: Sized { Ok(false) } - #[allow(unused_variables)] - async fn channel_open_forwarded_streamlocal( - &mut self, - channel: Channel, - socket_path: &str, - session: &mut Session, - ) -> Result { - Ok(false) - } - /// Called when the client confirmed our request to open a /// channel. A channel can only be written to after receiving this /// message (this library panics otherwise). @@ -537,8 +527,7 @@ pub trait Handler: Sized { #[allow(unused_variables)] async fn streamlocal_forward( &mut self, - server_socket_path: &str, - client_socket_path: &mut str, + socket_path: &str, session: &mut Session, ) -> Result { Ok(false) diff --git a/russh/src/server/session.rs b/russh/src/server/session.rs index 45d22459..cac70d5e 100644 --- a/russh/src/server/session.rs +++ b/russh/src/server/session.rs @@ -44,7 +44,6 @@ pub enum Msg { }, ChannelOpenForwardedStreamLocal { server_socket_path: String, - client_socket_path: String, channel_ref: ChannelRef, }, ChannelOpenX11 { @@ -185,6 +184,27 @@ impl Handle { } } + /// Notifies the client that it can no longer open TCP/IP forwarding channel for a port. + pub async fn cancel_forward_tcpip(&self, address: String, port: u32) -> Result<(), ()> { + let (reply_send, reply_recv) = oneshot::channel(); + self.sender + .send(Msg::CancelTcpIpForward { + reply_channel: Some(reply_send), + address, + port, + }) + .await + .map_err(|_| ())?; + match reply_recv.await { + Ok(true) => Ok(()), + Ok(false) => Err(()), // crate::Error::RequestDenied + Err(e) => { + error!("Unable to receive CancelTcpIpForward result: {e:?}"); + Err(()) // crate::Error::Disconnect + } + } + } + /// Request a session channel (the most basic type of /// channel). This function returns `Ok(..)` immediately if the /// connection is authenticated, but the channel only becomes @@ -259,10 +279,9 @@ impl Handle { .await } - pub async fn channel_open_forwarded_streamlocal, B: Into>( + pub async fn channel_open_forwarded_streamlocal>( &self, server_socket_path: A, - client_socket_path: B, ) -> Result, Error> { let (sender, receiver) = unbounded_channel(); let channel_ref = ChannelRef::new(sender); @@ -271,7 +290,6 @@ impl Handle { self.sender .send(Msg::ChannelOpenForwardedStreamLocal { server_socket_path: server_socket_path.into(), - client_socket_path: client_socket_path.into(), channel_ref, }) .await @@ -528,7 +546,7 @@ impl Session { let id = self.channel_open_forwarded_tcpip(&connected_address, connected_port, &originator_address, originator_port)?; self.channels.insert(id, channel_ref); } - Some(Msg::ChannelOpenForwardedStreamLocal { server_socket_path, client_socket_path: _, channel_ref }) => { + Some(Msg::ChannelOpenForwardedStreamLocal { server_socket_path, channel_ref }) => { let id = self.channel_open_forwarded_streamlocal(&server_socket_path)?; self.channels.insert(id, channel_ref); } @@ -930,10 +948,10 @@ impl Session { pub fn channel_open_forwarded_streamlocal( &mut self, - client_socket_path: &str, + socket_path: &str, ) -> Result { - self.channel_open_generic(b"forwarded-streamlocal", |write| { - write.extend_ssh_string(client_socket_path.as_bytes()); + self.channel_open_generic(b"forwarded-streamlocal@openssh.com", |write| { + write.extend_ssh_string(socket_path.as_bytes()); write.extend_ssh_string(b""); }) }