Support running server side with sudo
This allows forwarding ports that you would otherwise not be able to see. More dangerous, probably not what you want most of the time, but OK for now. (I continue to resist adding clap as a dependency.)
This commit is contained in:
parent
d3d7b4f137
commit
ec130d38b9
2 changed files with 62 additions and 28 deletions
|
|
@ -275,6 +275,7 @@ async fn client_main<Reader: AsyncRead + Unpin, Writer: AsyncWrite + Unpin>(
|
|||
|
||||
async fn spawn_ssh(
|
||||
server: &str,
|
||||
sudo: bool,
|
||||
) -> Result<(tokio::process::Child, u16), std::io::Error> {
|
||||
let socks_port = {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await?;
|
||||
|
|
@ -285,9 +286,11 @@ async fn spawn_ssh(
|
|||
cmd.arg("-T")
|
||||
.arg("-D")
|
||||
.arg(socks_port.to_string())
|
||||
.arg(server)
|
||||
.arg("fwd")
|
||||
.arg("--server");
|
||||
.arg(server);
|
||||
if sudo {
|
||||
cmd.arg("sudo");
|
||||
}
|
||||
cmd.arg("fwd").arg("--server");
|
||||
|
||||
cmd.stdout(std::process::Stdio::piped());
|
||||
cmd.stdin(std::process::Stdio::piped());
|
||||
|
|
@ -314,12 +317,16 @@ fn is_sigint(status: std::process::ExitStatus) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
async fn client_connect_loop(remote: &str, events: mpsc::Sender<ui::UIEvent>) {
|
||||
async fn client_connect_loop(
|
||||
remote: &str,
|
||||
sudo: bool,
|
||||
events: mpsc::Sender<ui::UIEvent>,
|
||||
) {
|
||||
loop {
|
||||
_ = events.send(ui::UIEvent::Disconnected).await;
|
||||
|
||||
let (mut child, socks_port) =
|
||||
spawn_ssh(remote).await.expect("failed to spawn");
|
||||
spawn_ssh(remote, sudo).await.expect("failed to spawn");
|
||||
|
||||
let mut stderr = child
|
||||
.stderr
|
||||
|
|
@ -377,7 +384,7 @@ async fn client_connect_loop(remote: &str, events: mpsc::Sender<ui::UIEvent>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn run_client(remote: &str) {
|
||||
pub async fn run_client(remote: &str, sudo: bool) {
|
||||
let (event_sender, event_receiver) = mpsc::channel(1024);
|
||||
_ = log::set_boxed_logger(ui::Logger::new(event_sender.clone()));
|
||||
log::set_max_level(LevelFilter::Info);
|
||||
|
|
@ -395,7 +402,7 @@ pub async fn run_client(remote: &str) {
|
|||
// Start the reconnect loop.
|
||||
tokio::select! {
|
||||
_ = ui.run() => (),
|
||||
_ = client_connect_loop(remote, event_sender) => ()
|
||||
_ = client_connect_loop(remote, sudo, event_sender) => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
69
src/main.rs
69
src/main.rs
|
|
@ -5,7 +5,7 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||
|
||||
fn usage() {
|
||||
println!(indoc! {"
|
||||
usage: fwd [--version] (<server> | browse <url>)
|
||||
usage: fwd [options] (<server> | browse <url>)
|
||||
|
||||
To connect a client to a server that has an `fwd` installed in its path, run
|
||||
`fwd <server>` on the client, where <server> is the name of the server to
|
||||
|
|
@ -13,6 +13,15 @@ connect to.
|
|||
|
||||
On a server that already has a client connected to it you can use `fwd browse
|
||||
<url>` to open `<url>` in the default browser of the client.
|
||||
|
||||
Options:
|
||||
--version Print the version of fwd and exit
|
||||
--sudo, -s Run the server side of fwd with `sudo`. This allows the
|
||||
client to forward ports that are open by processes being
|
||||
run under other accounts (e.g., docker containers being
|
||||
run as root), but requires sudo access on the server and
|
||||
*might* end up forwarding ports that you do not want
|
||||
forwarded (e.g., port 22 for sshd, or port 53 for systemd.)
|
||||
"});
|
||||
}
|
||||
|
||||
|
|
@ -21,33 +30,46 @@ enum Args {
|
|||
Help,
|
||||
Version,
|
||||
Server,
|
||||
Client(String),
|
||||
Client(String, bool),
|
||||
Browse(String),
|
||||
Error,
|
||||
}
|
||||
|
||||
fn parse_args(args: Vec<String>) -> Args {
|
||||
// Look for help; allow it to come anywhere because sometimes you just
|
||||
// want to jam it on the end of an existing command line.
|
||||
for arg in &args {
|
||||
let mut server = None;
|
||||
let mut sudo = None;
|
||||
let mut rest = Vec::new();
|
||||
|
||||
for arg in args.into_iter().skip(1) {
|
||||
if arg == "--help" || arg == "-?" || arg == "-h" {
|
||||
return Args::Help;
|
||||
} else if arg == "--version" {
|
||||
return Args::Version;
|
||||
} else if arg == "--server" {
|
||||
server = Some(true)
|
||||
} else if arg == "--sudo" || arg == "-s" {
|
||||
sudo = Some(true)
|
||||
} else {
|
||||
rest.push(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// No help, parse for reals.
|
||||
if args.len() >= 2 && args[1] == "--version" {
|
||||
Args::Version
|
||||
} else if args.len() == 2 && &args[1] == "--server" {
|
||||
Args::Server
|
||||
} else if args.len() == 3 && args[1] == "browse" {
|
||||
Args::Browse(args[2].to_string())
|
||||
} else {
|
||||
if args.len() != 2 {
|
||||
Args::Error
|
||||
if server.unwrap_or(false) {
|
||||
if rest.len() == 0 && sudo.is_none() {
|
||||
Args::Server
|
||||
} else {
|
||||
Args::Client(args[1].to_string())
|
||||
Args::Error
|
||||
}
|
||||
} else if rest.len() > 1 && rest[0] == "browse" {
|
||||
if rest.len() == 2 {
|
||||
Args::Browse(rest[1].to_string())
|
||||
} else {
|
||||
Args::Error
|
||||
}
|
||||
} else if rest.len() == 1 {
|
||||
Args::Client(rest[0].to_string(), sudo.unwrap_or(false))
|
||||
} else {
|
||||
Args::Error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,8 +88,8 @@ async fn main() {
|
|||
Args::Browse(url) => {
|
||||
fwd::browse_url(&url).await;
|
||||
}
|
||||
Args::Client(server) => {
|
||||
fwd::run_client(&server).await;
|
||||
Args::Client(server, sudo) => {
|
||||
fwd::run_client(&server, sudo).await;
|
||||
}
|
||||
Args::Error => {
|
||||
usage();
|
||||
|
|
@ -111,13 +133,18 @@ mod tests {
|
|||
assert_arg_parse!(&["browse", "google.com", "what"], Args::Error);
|
||||
assert_arg_parse!(&["a", "b"], Args::Error);
|
||||
assert_arg_parse!(&["--server", "something"], Args::Error);
|
||||
assert_arg_parse!(&["--server", "--sudo"], Args::Error);
|
||||
assert_arg_parse!(&["--server", "-s"], Args::Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client() {
|
||||
assert_arg_parse!(&["foo.com"], Args::Client(_));
|
||||
assert_arg_parse!(&["a"], Args::Client(_));
|
||||
assert_arg_parse!(&["browse"], Args::Client(_));
|
||||
assert_arg_parse!(&["foo.com"], Args::Client(_, false));
|
||||
assert_arg_parse!(&["a"], Args::Client(_, false));
|
||||
assert_arg_parse!(&["browse"], Args::Client(_, false));
|
||||
assert_arg_parse!(&["foo.com", "--sudo"], Args::Client(_, true));
|
||||
assert_arg_parse!(&["a", "-s"], Args::Client(_, true));
|
||||
assert_arg_parse!(&["-s", "browse"], Args::Client(_, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue