diff --git a/Cargo.lock b/Cargo.lock index 5e494f4..95e246c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -371,9 +371,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -393,9 +393,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -1776,7 +1776,7 @@ dependencies = [ [[package]] name = "iroh-ssh" -version = "0.2.10" +version = "0.2.11" dependencies = [ "anyhow", "clap", @@ -1785,6 +1785,7 @@ dependencies = [ "iroh", "libc", "rand 0.9.2", + "regex", "runas", "self-runas", "tempfile", @@ -1873,17 +1874,16 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags", "libc", ] @@ -1987,13 +1987,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2161,7 +2161,7 @@ dependencies = [ "pin-project-lite", "serde", "snafu", - "socket2 0.6.0", + "socket2 0.6.3", "time", "tokio", "tokio-util", @@ -2475,7 +2475,7 @@ dependencies = [ "serde", "smallvec", "snafu", - "socket2 0.6.0", + "socket2 0.6.3", "time", "tokio", "tokio-util", @@ -2689,11 +2689,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3231,12 +3243,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3313,6 +3325,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "2.0.117" @@ -3501,25 +3519,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.0", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -3661,11 +3679,12 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", + "symlink", "thiserror 2.0.12", "time", "tracing-subscriber", @@ -4000,9 +4019,9 @@ dependencies = [ [[package]] name = "whoami" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a5b12f9df4f978d2cfdb1bd3bac52433f44393342d7ee9c25f5a1c14c0f45d" +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" dependencies = [ "libc", "libredox", @@ -4213,13 +4232,13 @@ dependencies = [ [[package]] name = "windows-service" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193cae8e647981c35bc947fdd57ba7928b1fa0d4a79305f6dd2dc55221ac35ac" +checksum = "857224b3b211c6f3616921f081ee54721ee3ad2ace2fac6a6337e032f7b4dcf2" dependencies = [ "bitflags", "widestring", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index eedcebd..dacbf50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/rustonbsd/iroh-ssh" readme = "README.md" keywords = ["networking"] categories = ["network-programming"] -version = "0.2.10" +version = "0.2.11" edition = "2024" [dependencies] @@ -18,23 +18,24 @@ rand = "0.9" tokio-stream = { version = "0.1.18", features = ["sync"] } tracing = "0.1.44" tracing-subscriber = { version = "0.3.23", features = ["fmt", "ansi"] } -tracing-appender = "0.2.4" -tokio = { version = "1.50.0", features = [ +tracing-appender = "0.2.5" +tokio = { version = "1.52.3", features = [ "macros", "io-util", "sync", "rt", ] } -clap = { version = "4.6.0", features = ["derive"] } +clap = { version = "4.6.1", features = ["derive"] } homedir = "0.3.6" -whoami = "2.1.1" +whoami = "2.1.2" z32 = "1.3" runas = "1.2.0" tempfile = "3.27.0" self-runas = "0.1" +regex = "1.12.3" [target.'cfg(windows)'.dependencies.windows-service] -version = "0.8.0" +version = "0.8.1" [target.'cfg(windows)'.dependencies.windows-sys] version = "0.61.2" @@ -53,7 +54,7 @@ features = [ ] [target.'cfg(unix)'.dependencies.libc] -version = "0.2.183" +version = "0.2.186" [profile.release] opt-level = 3 diff --git a/README.md b/README.md index 3c8eaee..60d00c3 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Documentation](https://docs.rs/iroh-ssh/badge.svg)](https://docs.rs/iroh-ssh) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE) [![AUR](https://img.shields.io/aur/version/iroh-ssh-git)](https://aur.archlinux.org/packages/iroh-ssh-git) +[![Discord](https://img.shields.io/discord/1403836127458099381?logo=discord&label=Discord)](https://discord.gg/eyC7nku3C) **SSH to any machine without ip, behind a NAT/firewall without port forwarding or VPN setup.** @@ -43,7 +44,7 @@ Download and setup the binary automatically for your operating system from [GitH Linux ```bash # Linux -wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.linux +wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.linux chmod +x iroh-ssh.linux sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh ``` @@ -51,7 +52,7 @@ sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh macOS ```bash # macOS arm -curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.macos +curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.macos chmod +x iroh-ssh.macos sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh ``` @@ -59,7 +60,7 @@ sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh Windows ```bash # Windows x86 64bit -curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.exe +curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.exe mkdir %LOCALAPPDATA%\iroh-ssh move iroh-ssh.exe %LOCALAPPDATA%\iroh-ssh\ setx PATH "%PATH%;%LOCALAPPDATA%\iroh-ssh" @@ -141,7 +142,7 @@ Display its Endpoint ID and share it to allow connection > iroh-ssh info Your iroh-ssh endpoint id: 38b7dc10df96005255c3beaeaeef6cfebd88344aa8c85e1dbfc1ad5e50f372ac - iroh-ssh version 0.2.10 + iroh-ssh version 0.2.11 https://github.com/rustonbsd/iroh-ssh Your server iroh-ssh endpoint id: diff --git a/README_es.md b/README_es.md index 586cb6d..8ae8850 100644 --- a/README_es.md +++ b/README_es.md @@ -5,6 +5,7 @@ [![Documentation](https://docs.rs/iroh-ssh/badge.svg)](https://docs.rs/iroh-ssh) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE) [![AUR](https://img.shields.io/aur/version/iroh-ssh-git)](https://aur.archlinux.org/packages/iroh-ssh-git) +[![Discord](https://img.shields.io/discord/1403836127458099381?logo=discord&label=Discord)](https://discord.gg/eyC7nku3C) **Usa SSH a cualquier maquina sin usar IP, tras una NAT/firewall y sin requerir redireccionamiento de puertos o configurar una VPN.** @@ -43,7 +44,7 @@ Descarga y configura automáticamente el binario para tu sistema operativo desde Linux ```bash # Linux -wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.linux +wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.linux chmod +x iroh-ssh.linux sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh ``` @@ -51,7 +52,7 @@ sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh macOS ```bash # macOS arm -curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.macos +curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.macos chmod +x iroh-ssh.macos sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh ``` @@ -59,7 +60,7 @@ sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh Windows ```bash # Windows x86 64bit -curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.exe +curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.exe mkdir %LOCALAPPDATA%\iroh-ssh move iroh-ssh.exe %LOCALAPPDATA%\iroh-ssh\ setx PATH "%PATH%;%LOCALAPPDATA%\iroh-ssh" @@ -141,7 +142,7 @@ Mostrar su ID de nodo y compártalo para permitir la conexión > iroh-ssh info Your iroh-ssh endpoint id: 38b7dc10df96005255c3beaeaeef6cfebd88344aa8c85e1dbfc1ad5e50f372ac - iroh-ssh version 0.2.10 + iroh-ssh version 0.2.11 https://github.com/rustonbsd/iroh-ssh Your server iroh-ssh endpoint id: diff --git a/README_pt.md b/README_pt.md index 3309db3..2880a75 100644 --- a/README_pt.md +++ b/README_pt.md @@ -5,6 +5,7 @@ [![Documentation](https://docs.rs/iroh-ssh/badge.svg)](https://docs.rs/iroh-ssh) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE) [![AUR](https://img.shields.io/aur/version/iroh-ssh-git)](https://aur.archlinux.org/packages/iroh-ssh-git) +[![Discord](https://img.shields.io/discord/1403836127458099381?logo=discord&label=Discord)](https://discord.gg/eyC7nku3C) **Acesse qualquer máquina sem IP, atrás de um NAT/firewall, sem redirecionamento de portas ou configuração de VPN.** @@ -43,7 +44,7 @@ Baixe e configure automaticamente o binário para o seu sistema operacional a pa Linux ```bash # Linux -wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.linux +wget https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.linux chmod +x iroh-ssh.linux sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh ``` @@ -51,7 +52,7 @@ sudo mv iroh-ssh.linux /usr/local/bin/iroh-ssh macOS ```bash # macOS arm -curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.macos +curl -LJO https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.macos chmod +x iroh-ssh.macos sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh ``` @@ -59,7 +60,7 @@ sudo mv iroh-ssh.macos /usr/local/bin/iroh-ssh Windows ```bash # Windows x86 64bit -curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.10/iroh-ssh.exe +curl -L -o iroh-ssh.exe https://github.com/rustonbsd/iroh-ssh/releases/download/0.2.11/iroh-ssh.exe mkdir %LOCALAPPDATA%\iroh-ssh move iroh-ssh.exe %LOCALAPPDATA%\iroh-ssh\ setx PATH "%PATH%;%LOCALAPPDATA%\iroh-ssh" @@ -141,7 +142,7 @@ Exiba seu ID de nó e compartilhe-o para permitir a conexão > iroh-ssh info Your iroh-ssh endpoint id: 38b7dc10df96005255c3beaeaeef6cfebd88344aa8c85e1dbfc1ad5e50f372ac - iroh-ssh version 0.2.10 + iroh-ssh version 0.2.11 https://github.com/rustonbsd/iroh-ssh Your server iroh-ssh endpoint id: diff --git a/nix/package.nix b/nix/package.nix index da3512c..a42f078 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -12,16 +12,16 @@ rustPlatform.buildRustPackage (finalAttrs: { pname = "iroh-ssh"; - version = "0.2.10"; + version = "0.2.11"; src = fetchFromGitHub { owner = "rustonbsd"; repo = "iroh-ssh"; tag = finalAttrs.version; - hash = "sha256-A/QdpPHI9TCqQ2oghxPUJl4KKX8gqkA3kBvN8f1Kegg="; + hash = "sha256-0FbezMQcbqhK6bmfP80R3gbGqbkBewprLqzITKwGCSI="; }; - cargoHash = "sha256-/cq/rOzrQ4t0qvdaqM3JhRn8IMncx7jWYDjdYmLCYvc="; + cargoHash = "sha256-2NAl4ClPN+OI1EBAkuL/KSiByxU34sBmYDjnRXYuiOY="; nativeBuildInputs = [ autoAddDriverRunpath diff --git a/src/api.rs b/src/api.rs index 80fed59..6cbb44b 100644 --- a/src/api.rs +++ b/src/api.rs @@ -185,7 +185,7 @@ pub async fn client_mode(connect_args: ConnectArgs) -> anyhow::Result<()> { .extra_relay_urls(parse_relay_urls(&connect_args.extra_relay_url)?) .build() .await?; - let mut ssh_process = iroh_ssh + let mut ssh_process = match iroh_ssh .start_ssh( connect_args.target, connect_args.ssh, @@ -193,11 +193,26 @@ pub async fn client_mode(connect_args: ConnectArgs) -> anyhow::Result<()> { &connect_args.relay_url, &connect_args.extra_relay_url, ) - .await?; + .await + { + Ok(child) => child, + Err(err) => match err.kind() { + std::io::ErrorKind::NotFound => { + eprintln!( + "SSH command not found, please make sure your system has an SSH client installed and and that the exact cmd \"ssh\" is in your PATH" + ); + std::process::exit(1); + } + _ => { + eprintln!("Unknown failure when calling the SSH client: {err}"); + std::process::exit(1); + } + }, + }; let status = ssh_process.wait().await?; - // this kills the process (ok is just here for now compile errors) + // this kills the process (ok is just here for no compile errors) exit_with_code(status); Ok(()) diff --git a/src/ssh.rs b/src/ssh.rs index fae0fd7..36232c7 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,9 +1,10 @@ use crate::{Builder, Inner, IrohSsh, cli::SshOpts}; -use std::{ffi::OsString, path::Path, process::Stdio}; +use std::{ffi::OsString, io, path::Path, process::Stdio, time::Duration}; use anyhow::bail; use ed25519_dalek::SECRET_KEY_LENGTH; use homedir::my_home; +use regex::Regex; use std::sync::Arc; use iroh::{ @@ -12,7 +13,7 @@ use iroh::{ protocol::{ProtocolHandler, Router}, }; use tokio::{ - io::AsyncWriteExt, + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, net::TcpStream, process::{Child, Command}, }; @@ -114,6 +115,10 @@ impl Builder { }; let router = if self.accept_incoming { + if is_ssh_server_available(iroh_ssh.ssh_port, Duration::from_secs(10)).await.is_err() { + eprintln!("SSH server not available on port {}, incoming connections will fail. Please ensure you have an SSH server installed and running on port {}.", iroh_ssh.ssh_port, iroh_ssh.ssh_port); + bail!("no ssh server available on specified port") + } Router::builder(endpoint.clone()).accept(IrohSsh::ALPN(), iroh_ssh.clone()) } else { Router::builder(endpoint.clone()) @@ -126,6 +131,27 @@ impl Builder { } } +async fn is_ssh_server_available(port: u16, timeout: Duration) -> anyhow::Result<()> { + tokio::time::timeout(timeout, async { + let stream = TcpStream::connect(format!("localhost:{port}")).await?; + let mut reader = BufReader::new(stream); + let mut line_buf = String::new(); + let regex = Regex::new(r"^SSH-\d+\.\d+-").expect("valid regex"); + + loop { + line_buf.clear(); + if reader.read_line(&mut line_buf).await? == 0 { + bail!("SSH server closed the connection"); + } + if regex.is_match(&line_buf) { + reader.shutdown().await.ok(); + return Ok(()); + } + } + }) + .await? +} + impl Default for Builder { fn default() -> Self { Self::new() @@ -153,7 +179,7 @@ impl IrohSsh { remote_cmd: Vec, relay_urls: &[String], extra_relay_urls: &[String], - ) -> anyhow::Result { + ) -> io::Result { let c_exe = std::env::current_exe()?; let mut cmd = build_ssh_command( &c_exe,