Skip to main content

iroh_ssh/
cli.rs

1use std::{ffi::OsString, path::PathBuf};
2
3use clap::{ArgAction, Args, Parser, Subcommand};
4
5const TARGET_HELP: &str = "Target in the form user@ENDPOINT_ID";
6const RELAY_URL_HELP: &str = "Use only these relay servers, replacing the defaults (repeatable)";
7const EXTRA_RELAY_URL_HELP: &str = "Add relay servers alongside the defaults (repeatable)";
8const KEY_DIR_HELP: &str = "Directory for iroh-ssh identity keys (default: ~/.ssh)";
9
10#[derive(Parser, Debug)]
11#[command(name = "iroh-ssh", about = "ssh without ip")]
12pub struct Cli {
13    #[command(subcommand)]
14    pub cmd: Option<Cmd>,
15
16    #[arg(help = TARGET_HELP)]
17    pub target: Option<String>,
18
19    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
20    pub relay_url: Vec<String>,
21
22    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
23    pub extra_relay_url: Vec<String>,
24
25    #[command(flatten)]
26    pub ssh: SshOpts,
27
28    #[arg(trailing_var_arg = true)]
29    pub remote_cmd: Option<Vec<OsString>>,
30}
31
32#[derive(Subcommand, Debug)]
33pub enum Cmd {
34    Connect(ConnectArgs),
35    #[command(hide = true)]
36    Exec(ExecArgs),
37    Server(ServerArgs),
38    Service {
39        #[command(subcommand)]
40        op: ServiceCmd,
41    },
42    Info(InfoArgs),
43    #[command(hide = true)]
44    Proxy(ProxyArgs),
45    #[command(hide = true)]
46    RunService(ServiceArgs),
47    Version,
48}
49
50#[derive(Args, Clone, Debug)]
51pub struct ProxyArgs {
52    #[arg(help = "Proxy Endpoint ID")]
53    pub endpoint_id: String,
54
55    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
56    pub relay_url: Vec<String>,
57
58    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
59    pub extra_relay_url: Vec<String>,
60}
61
62#[derive(Args, Clone, Debug)]
63pub struct ConnectArgs {
64    #[arg(help = TARGET_HELP)]
65    pub target: String,
66
67    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
68    pub relay_url: Vec<String>,
69
70    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
71    pub extra_relay_url: Vec<String>,
72
73    #[command(flatten)]
74    pub ssh: SshOpts,
75
76    #[arg(trailing_var_arg = true)]
77    pub remote_cmd: Vec<OsString>,
78}
79
80#[derive(Args, Clone, Debug)]
81pub struct ExecArgs {
82    #[arg(help = TARGET_HELP)]
83    pub target: String,
84
85    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
86    pub relay_url: Vec<String>,
87
88    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
89    pub extra_relay_url: Vec<String>,
90
91    #[command(flatten)]
92    pub ssh: SshOpts,
93
94    #[arg(trailing_var_arg = true, required = true)]
95    pub remote_cmd: Vec<OsString>,
96}
97
98#[derive(Args, Clone, Default, Debug)]
99pub struct SshOpts {
100    #[arg(
101        short = 'i',
102        long,
103        value_name = "PATH",
104        help = "Identity file for publickey auth"
105    )]
106    pub identity_file: Option<PathBuf>,
107
108    #[arg(short = 'L', value_name = "LPORT:HOST:RPORT",
109        help = "Local forward [bind_addr:]lport:host:rport (host can't be endpoint_id yet)", action = ArgAction::Append)]
110    pub local_forward: Vec<String>,
111
112    #[arg(short = 'R', value_name = "RPORT:HOST:LPORT",
113        help = "Remote forward [bind_addr:]rport:host:lport  (host can't be endpoint_id yet)", action = ArgAction::Append)]
114    pub remote_forward: Vec<String>,
115
116    #[arg(
117        short = 'p',
118        long,
119        value_name = "PORT",
120        help = "Remote sshd port (default 22)"
121    )]
122    pub port: Option<u16>,
123
124    #[arg(
125        short = 'l',
126        value_name = "USER",
127        help = "Login user (lets rsync's `-l user host cmd` invocation work)"
128    )]
129    pub login_user: Option<String>,
130
131    #[arg(short = 'o', value_name = "KEY=VALUE",
132        help = "Pass an ssh option (repeatable)", action = ArgAction::Append)]
133    pub options: Vec<String>,
134
135    #[arg(short = 'A', help = "Enable agent forwarding", action = ArgAction::SetTrue)]
136    pub agent: bool,
137
138    #[arg(short = 'a', help = "Disable agent forwarding", action = ArgAction::SetTrue)]
139    pub no_agent: bool,
140
141    #[arg(short = 'X', help = "Enable X11 forwarding", action = ArgAction::SetTrue)]
142    pub x11: bool,
143
144    #[arg(short = 'Y', help = "Enable trusted X11 forwarding", action = ArgAction::SetTrue)]
145    pub x11_trusted: bool,
146
147    #[arg(short = 'N', help = "Do not execute remote command", action = ArgAction::SetTrue)]
148    pub no_cmd: bool,
149
150    #[arg(short = 't', help = "Force pseudo-terminal", action = ArgAction::SetTrue)]
151    pub force_tty: bool,
152
153    #[arg(short = 'T', help = "Disable pseudo-terminal", action = ArgAction::SetTrue)]
154    pub no_tty: bool,
155
156    #[arg(short = 'v', help = "Increase verbosity",
157        action = ArgAction::Count)]
158    pub verbose: u8,
159
160    #[arg(short = 'q', help = "Quiet mode", action = ArgAction::SetTrue)]
161    pub quiet: bool,
162}
163
164#[derive(Args, Clone, Debug)]
165pub struct ServerArgs {
166    #[arg(long, default_value = "22")]
167    pub ssh_port: u16,
168
169    #[arg(short, long, default_value_t = false)]
170    pub persist: bool,
171
172    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
173    pub key_dir: Option<PathBuf>,
174
175    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
176    pub relay_url: Vec<String>,
177
178    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
179    pub extra_relay_url: Vec<String>,
180}
181
182#[derive(Args, Clone, Debug)]
183pub struct InfoArgs {
184    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
185    pub key_dir: Option<PathBuf>,
186}
187
188#[derive(Subcommand, Clone, Debug)]
189pub enum ServiceCmd {
190    Install {
191        #[arg(long, default_value = "22")]
192        ssh_port: u16,
193
194        #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
195        key_dir: Option<PathBuf>,
196
197        #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
198        relay_url: Vec<String>,
199
200        #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
201        extra_relay_url: Vec<String>,
202    },
203    Uninstall,
204}
205
206#[derive(Args, Clone, Debug)]
207pub struct ServiceArgs {
208    #[arg(long, default_value = "22")]
209    pub ssh_port: u16,
210
211    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
212    pub key_dir: Option<PathBuf>,
213
214    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
215    pub relay_url: Vec<String>,
216
217    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
218    pub extra_relay_url: Vec<String>,
219}