From a8be2b0dcd47419b1425be964f2466f8a3e50cc8 Mon Sep 17 00:00:00 2001 From: Sean Estabrooks Date: Sat, 7 Sep 2024 07:12:00 -0400 Subject: [PATCH 1/3] Implement ProxyUseFDpass for ssh This allows the ProxyUseFDpass ssh config option, to be used on Linux and Mac OS. This was requested in enhancement issue #6093 --- Cargo.lock | 10 ++++++++++ wezterm-ssh/Cargo.toml | 3 +++ wezterm-ssh/src/sessioninner.rs | 13 +++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6535a2f229b..bebab660425 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3656,6 +3656,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "passfd" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b332c50e4d07c0011fff51ea305374408319908908bc1dbed7a0ffaaf63a8151" +dependencies = [ + "libc", +] + [[package]] name = "paste" version = "1.0.15" @@ -6479,6 +6488,7 @@ dependencies = [ "libssh-rs", "log", "once_cell", + "passfd", "portable-pty", "predicates", "regex", diff --git a/wezterm-ssh/Cargo.toml b/wezterm-ssh/Cargo.toml index bea299af985..57c24d6203c 100644 --- a/wezterm-ssh/Cargo.toml +++ b/wezterm-ssh/Cargo.toml @@ -40,6 +40,9 @@ wezterm-uds = { path = "../wezterm-uds" } # Not used directly, but is used to centralize the openssl vendor feature selection async_ossl = { path = "../async_ossl" } +[target.'cfg(unix)'.dependencies] +passfd = "0.1.6" + [dev-dependencies] assert_fs = "1.0.4" clap = {version="4.0", features=["derive"]} diff --git a/wezterm-ssh/src/sessioninner.rs b/wezterm-ssh/src/sessioninner.rs index 4ff213ad29b..227b9072d1e 100644 --- a/wezterm-ssh/src/sessioninner.rs +++ b/wezterm-ssh/src/sessioninner.rs @@ -357,11 +357,16 @@ impl SessionInner { #[cfg(unix)] unsafe { + use passfd::FdPassingExt; use std::os::unix::io::{FromRawFd, IntoRawFd}; - return Ok(( - Socket::from_raw_fd(a.into_raw_fd()), - Some(KillOnDropChild(child)), - )); + + let raw = a.into_raw_fd(); + let dest = match self.config.get("proxyusefdpass").map(|s| s.as_str()) { + Some("yes") => raw.recv_fd()?, + _ => raw, + }; + + return Ok((Socket::from_raw_fd(dest), Some(KillOnDropChild(child)))); } #[cfg(windows)] unsafe { From 26dd86b2094a50c56c7da49f316c7aab3904acd8 Mon Sep 17 00:00:00 2001 From: Sean Estabrooks Date: Sat, 7 Sep 2024 06:16:36 -0400 Subject: [PATCH 2/3] Don't pass ProxyCommand, just look it up It doesn't make much sense to pass this value, especially after adding the ProxyUseFDpass functionality, which accesses the config directly anyway. --- wezterm-ssh/src/sessioninner.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/wezterm-ssh/src/sessioninner.rs b/wezterm-ssh/src/sessioninner.rs index 227b9072d1e..87b028950e1 100644 --- a/wezterm-ssh/src/sessioninner.rs +++ b/wezterm-ssh/src/sessioninner.rs @@ -205,8 +205,7 @@ impl SessionInner { sess.set_option(libssh_rs::SshOption::HostKeys(host_key.to_string()))?; } - let (sock, _child) = - self.connect_to_host(&hostname, port, verbose, self.config.get("proxycommand"))?; + let (sock, _child) = self.connect_to_host(&hostname, port, verbose)?; let raw = { #[cfg(unix)] { @@ -288,8 +287,7 @@ impl SessionInner { )))) .context("notifying user of banner")?; - let (sock, _child) = - self.connect_to_host(&hostname, port, verbose, self.config.get("proxycommand"))?; + let (sock, _child) = self.connect_to_host(&hostname, port, verbose)?; let mut sess = ssh2::Session::new()?; if verbose { @@ -331,9 +329,8 @@ impl SessionInner { hostname: &str, port: u16, verbose: bool, - proxy_command: Option<&String>, ) -> anyhow::Result<(Socket, Option)> { - match proxy_command.map(|s| s.as_str()) { + match self.config.get("proxycommand").map(|s| s.as_str()) { Some("none") | None => {} Some(proxy_command) => { let mut cmd; From 3b3022fd7c56f5335b6345cf2bab2275e13ef99d Mon Sep 17 00:00:00 2001 From: Sean Estabrooks Date: Sat, 7 Sep 2024 06:14:50 -0400 Subject: [PATCH 3/3] Address some lint warnings from Clippy --- wezterm-ssh/src/sessioninner.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/wezterm-ssh/src/sessioninner.rs b/wezterm-ssh/src/sessioninner.rs index 87b028950e1..f2536a78efe 100644 --- a/wezterm-ssh/src/sessioninner.rs +++ b/wezterm-ssh/src/sessioninner.rs @@ -337,10 +337,10 @@ impl SessionInner { if cfg!(windows) { let comspec = std::env::var("COMSPEC").unwrap_or_else(|_| "cmd".to_string()); cmd = std::process::Command::new(comspec); - cmd.args(&["/c", proxy_command]); + cmd.args(["/c", proxy_command]); } else { cmd = std::process::Command::new("sh"); - cmd.args(&["-c", &format!("exec {}", proxy_command)]); + cmd.args(["-c", &format!("exec {}", proxy_command)]); } let (a, b) = socketpair()?; @@ -378,8 +378,7 @@ impl SessionInner { let addr = (hostname, port) .to_socket_addrs()? - .filter(|addr| self.filter_sock_addr(addr)) - .next() + .find(|addr| self.filter_sock_addr(addr)) .with_context(|| format!("resolving address for {}", hostname))?; if verbose { log::info!("resolved {hostname}:{port} -> {addr:?}"); @@ -388,8 +387,7 @@ impl SessionInner { if let Some(bind_addr) = self.config.get("bindaddress") { let bind_addr = (bind_addr.as_str(), 0) .to_socket_addrs()? - .filter(|addr| self.filter_sock_addr(addr)) - .next() + .find(|addr| self.filter_sock_addr(addr)) .with_context(|| format!("resolving bind address {bind_addr:?}"))?; if verbose { log::info!("binding to {bind_addr:?}");