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