summaryrefslogtreecommitdiffhomepage
path: root/mullvad-cli/src/cmds/split_tunnel
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-05-03 11:20:31 +0200
committerDavid Lönnhager <david.l@mullvad.net>2023-05-03 11:20:31 +0200
commit49ea114adddba1a1db6ffc6c440e743c01797a47 (patch)
tree66f1bf1e3e1d208e233e5622045503abe85a3a89 /mullvad-cli/src/cmds/split_tunnel
parentbeaa6d3b80d9c9dfed99c710c793830db3ddc7ec (diff)
parentaade46c9c73c874e4153caa450e713d8f8b37760 (diff)
downloadmullvadvpn-49ea114adddba1a1db6ffc6c440e743c01797a47.tar.xz
mullvadvpn-49ea114adddba1a1db6ffc6c440e743c01797a47.zip
Merge branch 'update-clap'
Diffstat (limited to 'mullvad-cli/src/cmds/split_tunnel')
-rw-r--r--mullvad-cli/src/cmds/split_tunnel/linux.rs99
-rw-r--r--mullvad-cli/src/cmds/split_tunnel/windows.rs207
2 files changed, 119 insertions, 187 deletions
diff --git a/mullvad-cli/src/cmds/split_tunnel/linux.rs b/mullvad-cli/src/cmds/split_tunnel/linux.rs
index 8b235f1027..5a66d899ab 100644
--- a/mullvad-cli/src/cmds/split_tunnel/linux.rs
+++ b/mullvad-cli/src/cmds/split_tunnel/linux.rs
@@ -1,82 +1,61 @@
-use crate::{new_rpc_client, Command, Result};
+use anyhow::Result;
+use clap::Subcommand;
+use mullvad_management_interface::MullvadProxyClient;
-pub struct SplitTunnel;
-
-#[mullvad_management_interface::async_trait]
-impl Command for SplitTunnel {
- fn name(&self) -> &'static str {
- "split-tunnel"
- }
-
- fn clap_subcommand(&self) -> clap::App<'static> {
- clap::App::new(self.name())
- .about(
- "Manage split tunneling. To launch applications outside \
- the tunnel, use the program 'mullvad-exclude' instead of this command.",
- )
- .setting(clap::AppSettings::SubcommandRequiredElseHelp)
- .subcommand(create_pid_subcommand())
- }
-
- async fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
- match matches.subcommand() {
- Some(("pid", pid_matches)) => Self::handle_pid_cmd(pid_matches).await,
- _ => unreachable!("unhandled command"),
- }
- }
-}
-
-fn create_pid_subcommand() -> clap::App<'static> {
- clap::App::new("pid")
- .about("Manage processes to exclude from the tunnel")
- .setting(clap::AppSettings::SubcommandRequiredElseHelp)
- .subcommand(clap::App::new("add").arg(clap::Arg::new("pid").required(true)))
- .subcommand(clap::App::new("delete").arg(clap::Arg::new("pid").required(true)))
- .subcommand(clap::App::new("clear"))
- .subcommand(clap::App::new("list"))
+/// Manage split tunneling. To launch applications outside the tunnel, use the program
+/// 'mullvad-exclude' instead of this command
+#[derive(Subcommand, Debug)]
+pub enum SplitTunnel {
+ /// List all processes that are excluded from the tunnel
+ List,
+ /// Add a PID to exclude from the tunnel
+ Add { pid: i32 },
+ /// Stop excluding a PID from the tunnel
+ Delete { pid: i32 },
+ /// Stop excluding all processes from the tunnel
+ Clear,
}
impl SplitTunnel {
- async fn handle_pid_cmd(matches: &clap::ArgMatches) -> Result<()> {
- match matches.subcommand() {
- Some(("add", matches)) => {
- let pid: i32 = matches.value_of_t_or_exit("pid");
- new_rpc_client()
+ pub async fn handle(self) -> Result<()> {
+ match self {
+ SplitTunnel::List => {
+ let pids = MullvadProxyClient::new()
.await?
- .add_split_tunnel_process(pid)
+ .get_split_tunnel_processes()
.await?;
+
+ println!("Excluded PIDs:");
+ for pid in &pids {
+ println!("{pid}");
+ }
+
Ok(())
}
- Some(("delete", matches)) => {
- let pid: i32 = matches.value_of_t_or_exit("pid");
- new_rpc_client()
+ SplitTunnel::Add { pid } => {
+ MullvadProxyClient::new()
.await?
- .remove_split_tunnel_process(pid)
+ .add_split_tunnel_process(pid)
.await?;
+ println!("Excluding process");
Ok(())
}
- Some(("clear", _)) => {
- new_rpc_client()
+ SplitTunnel::Delete { pid } => {
+ MullvadProxyClient::new()
.await?
- .clear_split_tunnel_processes(())
+ .remove_split_tunnel_process(pid)
.await?;
+ println!("Stopped excluding process");
Ok(())
}
- Some(("list", _)) => {
- let mut pids_stream = new_rpc_client()
- .await?
- .get_split_tunnel_processes(())
+ SplitTunnel::Clear => {
+ MullvadProxyClient::new()
.await?
- .into_inner();
- println!("Excluded PIDs:");
-
- while let Some(pid) = pids_stream.message().await? {
- println!(" {pid}");
- }
-
+ .clear_split_tunnel_processes()
+ .await?;
+ println!("Stopped excluding all processes");
Ok(())
}
- _ => unreachable!("unhandled command"),
}
}
}
diff --git a/mullvad-cli/src/cmds/split_tunnel/windows.rs b/mullvad-cli/src/cmds/split_tunnel/windows.rs
index a133ab9682..f17a3382f3 100644
--- a/mullvad-cli/src/cmds/split_tunnel/windows.rs
+++ b/mullvad-cli/src/cmds/split_tunnel/windows.rs
@@ -1,157 +1,110 @@
-use std::{ffi::OsStr, path::Path};
+use anyhow::Result;
+use std::{
+ ffi::OsStr,
+ path::{Path, PathBuf},
+};
-use crate::{new_rpc_client, Command, Result};
+use clap::Subcommand;
+use mullvad_management_interface::MullvadProxyClient;
-pub struct SplitTunnel;
+use super::super::BooleanOption;
-#[mullvad_management_interface::async_trait]
-impl Command for SplitTunnel {
- fn name(&self) -> &'static str {
- "split-tunnel"
- }
+/// Set options for applications to exclude from the tunnel.
+#[derive(Subcommand, Debug)]
+pub enum SplitTunnel {
+ /// Display the split tunnel status and apps
+ Get {
+ /// List processes that are currently being excluded, as well as whether they are
+ /// excluded because of their executable paths or because they're subprocesses of
+ /// such processes
+ #[arg(long)]
+ list_processes: bool,
+ },
- fn clap_subcommand(&self) -> clap::App<'static> {
- clap::App::new(self.name())
- .about("Set options for applications to exclude from the tunnel")
- .setting(clap::AppSettings::SubcommandRequiredElseHelp)
- .subcommand(create_app_subcommand())
- .subcommand(
- clap::App::new("set")
- .about("Enable or disable split tunnel")
- .arg(
- clap::Arg::new("policy")
- .required(true)
- .possible_values(["on", "off"]),
- ),
- )
- .subcommand(clap::App::new("get").about("Display the split tunnel status"))
- .subcommand(create_pid_subcommand())
- }
+ /// Enable or disable split tunnel
+ Set { policy: BooleanOption },
- async fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
- match matches.subcommand() {
- Some(("app", matches)) => Self::handle_app_subcommand(matches).await,
- Some(("pid", matches)) => Self::handle_pid_subcommand(matches).await,
- Some(("get", _)) => self.get().await,
- Some(("set", matches)) => {
- let enabled = matches.value_of("policy").expect("missing policy");
- self.set(enabled == "on").await
- }
- _ => {
- unreachable!("unhandled command");
- }
- }
- }
-}
-
-fn create_app_subcommand() -> clap::App<'static> {
- clap::App::new("app")
- .about("Manage applications to exclude from the tunnel")
- .setting(clap::AppSettings::SubcommandRequiredElseHelp)
- .subcommand(clap::App::new("list"))
- .subcommand(clap::App::new("add").arg(clap::Arg::new("path").required(true)))
- .subcommand(clap::App::new("remove").arg(clap::Arg::new("path").required(true)))
- .subcommand(clap::App::new("clear"))
+ /// Manage applications to exclude from the tunnel
+ #[clap(subcommand)]
+ App(App),
}
-fn create_pid_subcommand() -> clap::App<'static> {
- clap::App::new("pid")
- .about("Manages processes (PIDs) excluded from the tunnel")
- .setting(clap::AppSettings::SubcommandRequiredElseHelp)
- .subcommand(clap::App::new("list")
- .about("List processes that are currently being excluded, i.e. their PIDs, as well as whether \
- they are excluded because of their executable paths or because they're subprocesses of \
- such processes"))
+#[derive(Subcommand, Debug)]
+pub enum App {
+ Add { path: PathBuf },
+ Remove { path: PathBuf },
+ Clear,
}
impl SplitTunnel {
- async fn handle_app_subcommand(matches: &clap::ArgMatches) -> Result<()> {
- match matches.subcommand() {
- Some(("list", _)) => {
- let paths = new_rpc_client()
- .await?
- .get_settings(())
- .await?
- .into_inner()
- .split_tunnel
- .unwrap()
- .apps;
+ pub async fn handle(self) -> Result<()> {
+ match self {
+ SplitTunnel::Get { list_processes } => {
+ let mut rpc = MullvadProxyClient::new().await?;
+ let settings = rpc.get_settings().await?.split_tunnel;
+
+ let enable_exclusions = BooleanOption::from(settings.enable_exclusions);
+
+ println!("Split tunneling state: {enable_exclusions}");
println!("Excluded applications:");
- for path in &paths {
- println!(" {}", path);
+ for path in &settings.apps {
+ println!("{}", path.display());
+ }
+
+ if list_processes {
+ let processes = rpc.get_excluded_processes().await?;
+ for process in &processes {
+ let subproc = if process.inherited { "subprocess" } else { "" };
+ println!(
+ "{:<7}{subproc:<12}{}",
+ process.pid,
+ Path::new(&process.image)
+ .file_name()
+ .unwrap_or(OsStr::new("unknown"))
+ .to_string_lossy()
+ );
+ }
}
Ok(())
}
- Some(("add", matches)) => {
- let path: String = matches.value_of_t_or_exit("path");
- new_rpc_client().await?.add_split_tunnel_app(path).await?;
+ SplitTunnel::Set { policy } => {
+ let mut rpc = MullvadProxyClient::new().await?;
+ rpc.set_split_tunnel_state(*policy).await?;
+ println!("Split tunnel policy: {policy}");
Ok(())
}
- Some(("remove", matches)) => {
- let path: String = matches.value_of_t_or_exit("path");
- new_rpc_client()
+ SplitTunnel::App(subcmd) => Self::app(subcmd).await,
+ }
+ }
+
+ async fn app(subcmd: App) -> Result<()> {
+ match subcmd {
+ App::Add { path } => {
+ MullvadProxyClient::new()
.await?
- .remove_split_tunnel_app(path)
+ .add_split_tunnel_app(path)
.await?;
+ println!("Added path to excluded apps list");
Ok(())
}
- Some(("clear", _)) => {
- new_rpc_client().await?.clear_split_tunnel_apps(()).await?;
+ App::Remove { path } => {
+ MullvadProxyClient::new()
+ .await?
+ .remove_split_tunnel_app(path)
+ .await?;
+ println!("Stopped excluding app from tunnel");
Ok(())
}
- _ => unreachable!("unhandled subcommand"),
- }
- }
-
- async fn handle_pid_subcommand(matches: &clap::ArgMatches) -> Result<()> {
- match matches.subcommand() {
- Some(("list", _)) => {
- let processes = new_rpc_client()
- .await?
- .get_excluded_processes(())
+ App::Clear => {
+ MullvadProxyClient::new()
.await?
- .into_inner();
-
- for process in &processes.processes {
- let subproc = if process.inherited { "subprocess" } else { "" };
- println!(
- "{:<7}{subproc:<12}{}",
- process.pid,
- Path::new(&process.image)
- .file_name()
- .unwrap_or(OsStr::new("unknown"))
- .to_string_lossy()
- );
- }
-
+ .clear_split_tunnel_apps()
+ .await?;
+ println!("Stopped excluding all apps");
Ok(())
}
- _ => unreachable!("unhandled subcommand"),
}
}
-
- async fn set(&self, enabled: bool) -> Result<()> {
- let mut rpc = new_rpc_client().await?;
- rpc.set_split_tunnel_state(enabled).await?;
- println!("Changed split tunnel setting");
- Ok(())
- }
-
- async fn get(&self) -> Result<()> {
- let mut rpc = new_rpc_client().await?;
- let enabled = rpc
- .get_settings(())
- .await?
- .into_inner()
- .split_tunnel
- .unwrap()
- .enable_exclusions;
- println!(
- "Split tunnel status: {}",
- if enabled { "on" } else { "off" }
- );
- Ok(())
- }
}