1use std::{ffi::OsString, path::PathBuf};
2
3use clap::{ArgAction, Args, Parser, Subcommand, command};
4
5const TARGET_HELP: &str = "Target in the form user@NODE_ID";
6
7#[derive(Parser, Debug)]
8#[command(name = "iroh-ssh", about = "ssh without ip")]
9pub struct Cli {
10 #[command(subcommand)]
11 pub cmd: Option<Cmd>,
12
13 #[arg(help = TARGET_HELP)]
14 pub target: Option<String>,
15
16 #[command(flatten)]
17 pub ssh: SshOpts,
18
19 #[arg(trailing_var_arg = true)]
20 pub remote_cmd: Option<Vec<OsString>>,
21}
22
23#[derive(Subcommand,Debug)]
24pub enum Cmd {
25 Connect(ConnectArgs),
26 #[command(hide = true)]
27 Exec(ExecArgs),
28 Server(ServerArgs),
29 Service {
30 #[command(subcommand)]
31 op: ServiceCmd,
32 },
33 Info,
34 #[command(hide = true)]
35 Proxy(ProxyArgs),
36 #[command(hide = true)]
37 RunService(ServiceArgs),
38}
39
40#[derive(Args, Clone, Debug)]
41pub struct ProxyArgs {
42 #[arg(help = "Proxy node ID")]
43 pub node_id: String,
44}
45
46#[derive(Args, Clone, Debug)]
47pub struct ConnectArgs {
48 #[arg(help = TARGET_HELP)]
49 pub target: String,
50
51 #[command(flatten)]
52 pub ssh: SshOpts,
53
54 #[arg(trailing_var_arg = true)]
55 pub remote_cmd: Vec<OsString>,
56}
57
58#[derive(Args, Clone, Debug)]
59pub struct ExecArgs {
60 #[arg(help = TARGET_HELP)]
61 pub target: String,
62
63 #[command(flatten)]
64 pub ssh: SshOpts,
65
66 #[arg(trailing_var_arg = true, required = true)]
67 pub remote_cmd: Vec<OsString>,
68}
69
70#[derive(Args, Clone, Default, Debug)]
71pub struct SshOpts {
72 #[arg(
73 short = 'i',
74 long,
75 value_name = "PATH",
76 help = "Identity file for publickey auth"
77 )]
78 pub identity_file: Option<PathBuf>,
79
80 #[arg(short = 'L', value_name = "LPORT:HOST:RPORT",
81 help = "Local forward [bind_addr:]lport:host:rport (host can't be node_id yet)", action = ArgAction::Append)]
82 pub local_forward: Vec<String>,
83
84 #[arg(short = 'R', value_name = "RPORT:HOST:LPORT",
85 help = "Remote forward [bind_addr:]rport:host:lport (host can't be node_id yet)", action = ArgAction::Append)]
86 pub remote_forward: Vec<String>,
87
88 #[arg(
89 short = 'p',
90 long,
91 value_name = "PORT",
92 help = "Remote sshd port (default 22)"
93 )]
94 pub port: Option<u16>,
95
96 #[arg(short = 'o', value_name = "KEY=VALUE",
97 help = "Pass an ssh option (repeatable)", action = ArgAction::Append)]
98 pub options: Vec<String>,
99
100 #[arg(short = 'A', help = "Enable agent forwarding", action = ArgAction::SetTrue)]
101 pub agent: bool,
102
103 #[arg(short = 'a', help = "Disable agent forwarding", action = ArgAction::SetTrue)]
104 pub no_agent: bool,
105
106 #[arg(short = 'X', help = "Enable X11 forwarding", action = ArgAction::SetTrue)]
107 pub x11: bool,
108
109 #[arg(short = 'Y', help = "Enable trusted X11 forwarding", action = ArgAction::SetTrue)]
110 pub x11_trusted: bool,
111
112 #[arg(short = 'N', help = "Do not execute remote command", action = ArgAction::SetTrue)]
113 pub no_cmd: bool,
114
115 #[arg(short = 't', help = "Force pseudo-terminal", action = ArgAction::SetTrue)]
116 pub force_tty: bool,
117
118 #[arg(short = 'T', help = "Disable pseudo-terminal", action = ArgAction::SetTrue)]
119 pub no_tty: bool,
120
121 #[arg(short = 'v', help = "Increase verbosity",
122 action = ArgAction::Count)]
123 pub verbose: u8,
124
125 #[arg(short = 'q', help = "Quiet mode", action = ArgAction::SetTrue)]
126 pub quiet: bool,
127}
128
129#[derive(Args, Clone, Debug)]
130pub struct ServerArgs {
131 #[arg(long, default_value = "22")]
132 pub ssh_port: u16,
133
134 #[arg(short, long, default_value_t = false)]
135 pub persist: bool,
136}
137
138#[derive(Subcommand, Clone, Debug)]
139pub enum ServiceCmd {
140 Install {
141 #[arg(long, default_value = "22")]
142 ssh_port: u16,
143 },
144 Uninstall,
145}
146
147#[derive(Args, Clone, Debug)]
148pub struct ServiceArgs {
149 #[arg(long, default_value = "22")]
150 pub ssh_port: u16,
151}