mirror of
https://github.com/xpn/Ouroboros
synced 2026-08-25 09:14:54 +00:00
117 lines
4.2 KiB
Diff
117 lines
4.2 KiB
Diff
Subject: [PATCH] client: add Handle::channel_open_forwarded_tcpip
|
|
|
|
Adds the ability for an SSH *client* to initiate a `forwarded-tcpip`
|
|
channel. The existing upstream API only lets clients open `session`,
|
|
`x11`, `direct-tcpip`, and `direct-streamlocal` channels — sufficient
|
|
for RFC 4254 conformance, where `forwarded-tcpip` is a server-initiated
|
|
channel sent in response to a prior `tcpip-forward` request.
|
|
|
|
Microsoft's Dev Tunnels protocol inverts that convention: the tunnel
|
|
*client* opens `forwarded-tcpip` directly to reach a known remote port
|
|
on the tunnel host. This patch makes that possible without touching
|
|
any private state — it mirrors exactly the shape of the existing
|
|
`channel_open_direct_tcpip` plumbing.
|
|
|
|
Applies against microsoft/vscode-russh `main` (commit fd4f608), which is
|
|
byte-identical to Eugeny/russh v0.37.1 in the files this patch touches.
|
|
|
|
---
|
|
russh/src/client/mod.rs | 37 +++++++++++++++++++++++++++++++++++++
|
|
russh/src/client/session.rs | 15 +++++++++++++++
|
|
2 files changed, 52 insertions(+)
|
|
|
|
diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs
|
|
--- a/russh/src/client/mod.rs
|
|
+++ b/russh/src/client/mod.rs
|
|
@@ -178,6 +178,13 @@ pub enum Msg {
|
|
originator_port: u32,
|
|
sender: UnboundedSender<ChannelMsg>,
|
|
},
|
|
+ ChannelOpenForwardedTcpIp {
|
|
+ connected_address: String,
|
|
+ connected_port: u32,
|
|
+ originator_address: String,
|
|
+ originator_port: u32,
|
|
+ sender: UnboundedSender<ChannelMsg>,
|
|
+ },
|
|
ChannelOpenDirectStreamLocal {
|
|
socket_path: String,
|
|
sender: UnboundedSender<ChannelMsg>,
|
|
@@ -511,6 +518,28 @@ impl<H: Handler> Handle<H> {
|
|
self.wait_channel_confirmation(receiver).await
|
|
}
|
|
|
|
+ /// Open a TCP/IP forwarding channel for a remotely forwarded port.
|
|
+ pub async fn channel_open_forwarded_tcpip<A: Into<String>, B: Into<String>>(
|
|
+ &self,
|
|
+ connected_address: A,
|
|
+ connected_port: u32,
|
|
+ originator_address: B,
|
|
+ originator_port: u32,
|
|
+ ) -> Result<Channel<Msg>, crate::Error> {
|
|
+ let (sender, receiver) = unbounded_channel();
|
|
+ self.sender
|
|
+ .send(Msg::ChannelOpenForwardedTcpIp {
|
|
+ connected_address: connected_address.into(),
|
|
+ connected_port,
|
|
+ originator_address: originator_address.into(),
|
|
+ originator_port,
|
|
+ sender,
|
|
+ })
|
|
+ .await
|
|
+ .map_err(|_| crate::Error::SendError)?;
|
|
+ self.wait_channel_confirmation(receiver).await
|
|
+ }
|
|
+
|
|
pub async fn channel_open_direct_streamlocal<S: Into<String>>(
|
|
&self,
|
|
socket_path: S,
|
|
@@ -890,6 +919,21 @@ impl Session {
|
|
)?;
|
|
self.channels.insert(id, sender);
|
|
}
|
|
+ Msg::ChannelOpenForwardedTcpIp {
|
|
+ connected_address,
|
|
+ connected_port,
|
|
+ originator_address,
|
|
+ originator_port,
|
|
+ sender,
|
|
+ } => {
|
|
+ let id = self.channel_open_forwarded_tcpip(
|
|
+ &connected_address,
|
|
+ connected_port,
|
|
+ &originator_address,
|
|
+ originator_port,
|
|
+ )?;
|
|
+ self.channels.insert(id, sender);
|
|
+ }
|
|
Msg::ChannelOpenDirectStreamLocal {
|
|
socket_path,
|
|
sender,
|
|
diff --git a/russh/src/client/session.rs b/russh/src/client/session.rs
|
|
--- a/russh/src/client/session.rs
|
|
+++ b/russh/src/client/session.rs
|
|
@@ -79,6 +79,21 @@ impl Session {
|
|
})
|
|
}
|
|
|
|
+ pub fn channel_open_forwarded_tcpip(
|
|
+ &mut self,
|
|
+ connected_address: &str,
|
|
+ connected_port: u32,
|
|
+ originator_address: &str,
|
|
+ originator_port: u32,
|
|
+ ) -> Result<ChannelId, crate::Error> {
|
|
+ self.channel_open_generic(b"forwarded-tcpip", |write| {
|
|
+ write.extend_ssh_string(connected_address.as_bytes());
|
|
+ write.push_u32_be(connected_port); // sender channel id.
|
|
+ write.extend_ssh_string(originator_address.as_bytes());
|
|
+ write.push_u32_be(originator_port); // sender channel id.
|
|
+ })
|
|
+ }
|
|
+
|
|
pub fn channel_open_direct_streamlocal(
|
|
&mut self,
|
|
socket_path: &str
|
|
|