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(short = 'o', value_name = "KEY=VALUE",
125        help = "Pass an ssh option (repeatable)", action = ArgAction::Append)]
126    pub options: Vec<String>,
127
128    #[arg(short = 'A', help = "Enable agent forwarding", action = ArgAction::SetTrue)]
129    pub agent: bool,
130
131    #[arg(short = 'a', help = "Disable agent forwarding", action = ArgAction::SetTrue)]
132    pub no_agent: bool,
133
134    #[arg(short = 'X', help = "Enable X11 forwarding", action = ArgAction::SetTrue)]
135    pub x11: bool,
136
137    #[arg(short = 'Y', help = "Enable trusted X11 forwarding", action = ArgAction::SetTrue)]
138    pub x11_trusted: bool,
139
140    #[arg(short = 'N', help = "Do not execute remote command", action = ArgAction::SetTrue)]
141    pub no_cmd: bool,
142
143    #[arg(short = 't', help = "Force pseudo-terminal", action = ArgAction::SetTrue)]
144    pub force_tty: bool,
145
146    #[arg(short = 'T', help = "Disable pseudo-terminal", action = ArgAction::SetTrue)]
147    pub no_tty: bool,
148
149    #[arg(short = 'v', help = "Increase verbosity",
150        action = ArgAction::Count)]
151    pub verbose: u8,
152
153    #[arg(short = 'q', help = "Quiet mode", action = ArgAction::SetTrue)]
154    pub quiet: bool,
155}
156
157#[derive(Args, Clone, Debug)]
158pub struct ServerArgs {
159    #[arg(long, default_value = "22")]
160    pub ssh_port: u16,
161
162    #[arg(short, long, default_value_t = false)]
163    pub persist: bool,
164
165    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
166    pub key_dir: Option<PathBuf>,
167
168    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
169    pub relay_url: Vec<String>,
170
171    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
172    pub extra_relay_url: Vec<String>,
173}
174
175#[derive(Args, Clone, Debug)]
176pub struct InfoArgs {
177    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
178    pub key_dir: Option<PathBuf>,
179}
180
181#[derive(Subcommand, Clone, Debug)]
182pub enum ServiceCmd {
183    Install {
184        #[arg(long, default_value = "22")]
185        ssh_port: u16,
186
187        #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
188        key_dir: Option<PathBuf>,
189
190        #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
191        relay_url: Vec<String>,
192
193        #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
194        extra_relay_url: Vec<String>,
195    },
196    Uninstall,
197}
198
199#[derive(Args, Clone, Debug)]
200pub struct ServiceArgs {
201    #[arg(long, default_value = "22")]
202    pub ssh_port: u16,
203
204    #[arg(long, value_name = "DIR", help = KEY_DIR_HELP)]
205    pub key_dir: Option<PathBuf>,
206
207    #[arg(long, value_name = "URL", help = RELAY_URL_HELP, action = ArgAction::Append)]
208    pub relay_url: Vec<String>,
209
210    #[arg(long, value_name = "URL", help = EXTRA_RELAY_URL_HELP, action = ArgAction::Append)]
211    pub extra_relay_url: Vec<String>,
212}