Skip to content

Commit

Permalink
kill and reap ProxyCommand
Browse files Browse the repository at this point in the history
Using the scopeguard crate ensures the child process (if any) spawned for
the ProxyCommand is cleaned up under all the various error scenarios
(such as auth failures etc), as well as in the normal successful use
case. This ensures killing it if necessary, and then waiting for it.
  • Loading branch information
daaku committed May 31, 2024
1 parent b8f94c4 commit 19d3bd2
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions wezterm-ssh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ wezterm-uds = { path = "../wezterm-uds" }

# Not used directly, but is used to centralize the openssl vendor feature selection
async_ossl = { path = "../async_ossl" }
scopeguard = "1.2.0"

[dev-dependencies]
assert_fs = "1.0.4"
Expand Down
29 changes: 22 additions & 7 deletions wezterm-ssh/src/sessioninner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ use filedescriptor::{
poll, pollfd, socketpair, AsRawSocketDescriptor, FileDescriptor, POLLIN, POLLOUT,
};
use portable_pty::ExitStatus;
use scopeguard::defer;
use smol::channel::{bounded, Receiver, Sender, TryRecvError};
use socket2::{Domain, Socket, Type};
use std::collections::{HashMap, VecDeque};
use std::io::{Read, Write};
use std::net::ToSocketAddrs;
use std::process::Child;
use std::time::Duration;

#[derive(Debug)]
Expand Down Expand Up @@ -205,8 +207,9 @@ impl SessionInner {
sess.set_option(libssh_rs::SshOption::HostKeys(host_key.to_string()))?;
}

let sock =
let (sock, child) =
self.connect_to_host(&hostname, port, verbose, self.config.get("proxycommand"))?;
defer! { clean_up_proxy_command_child(child); }
let raw = {
#[cfg(unix)]
{
Expand Down Expand Up @@ -288,8 +291,9 @@ impl SessionInner {
))))
.context("notifying user of banner")?;

let sock =
let (sock, child) =
self.connect_to_host(&hostname, port, verbose, self.config.get("proxycommand"))?;
defer! { clean_up_proxy_command_child(child); }

let mut sess = ssh2::Session::new()?;
if verbose {
Expand Down Expand Up @@ -332,7 +336,7 @@ impl SessionInner {
port: u16,
verbose: bool,
proxy_command: Option<&String>,
) -> anyhow::Result<Socket> {
) -> anyhow::Result<(Socket, Option<Child>)> {
match proxy_command.map(|s| s.as_str()) {
Some("none") | None => {}
Some(proxy_command) => {
Expand All @@ -351,19 +355,19 @@ impl SessionInner {
cmd.stdin(b.as_stdio()?);
cmd.stdout(b.as_stdio()?);
cmd.stderr(std::process::Stdio::inherit());
let _child = cmd
let child = cmd
.spawn()
.with_context(|| format!("spawning ProxyCommand {}", proxy_command))?;

#[cfg(unix)]
unsafe {
use std::os::unix::io::{FromRawFd, IntoRawFd};
return Ok(Socket::from_raw_fd(a.into_raw_fd()));
return Ok((Socket::from_raw_fd(a.into_raw_fd()), Some(child)));
}
#[cfg(windows)]
unsafe {
use std::os::windows::io::{FromRawSocket, IntoRawSocket};
return Ok(Socket::from_raw_socket(a.into_raw_socket()));
return Ok((Socket::from_raw_socket(a.into_raw_socket()), Some(Child)));
}
}
}
Expand Down Expand Up @@ -392,7 +396,7 @@ impl SessionInner {

sock.connect(&addr.into())
.with_context(|| format!("Connecting to {hostname}:{port} ({addr:?})"))?;
Ok(sock)
Ok((sock, None))
}

/// Used to restrict to_socket_addrs results to the address
Expand Down Expand Up @@ -1086,3 +1090,14 @@ where
}
Ok(true)
}

fn clean_up_proxy_command_child(child: Option<Child>) {
if let Some(mut child) = child {
if let Err(err) = child.kill() {
log::error!("Error killing ProxyCommand: {}", err);
}
if let Err(err) = child.wait() {
log::error!("Error waiting for ProxyCommand to finish: {}", err);
}
}
}

0 comments on commit 19d3bd2

Please sign in to comment.