summaryrefslogtreecommitdiffhomepage
path: root/mullvad-cli/src
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-05-29 09:45:17 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-07-02 09:54:19 +0200
commite5baa0e08816d535a031b3d8575701b8d43fb0c2 (patch)
treec4bf2ec1956977676bc25c2630bd38789f43dade /mullvad-cli/src
parent207ab239223686ff72c43a8a5d615565ab81b5ab (diff)
downloadmullvadvpn-e5baa0e08816d535a031b3d8575701b8d43fb0c2.tar.xz
mullvadvpn-e5baa0e08816d535a031b3d8575701b8d43fb0c2.zip
Support Windows split tunneling driver
Diffstat (limited to 'mullvad-cli/src')
-rw-r--r--mullvad-cli/src/cmds/mod.rs6
-rw-r--r--mullvad-cli/src/cmds/split_tunnel/mod.rs6
-rw-r--r--mullvad-cli/src/cmds/split_tunnel/windows.rs112
3 files changed, 120 insertions, 4 deletions
diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs
index bd7ca97372..2ceb3bfdcf 100644
--- a/mullvad-cli/src/cmds/mod.rs
+++ b/mullvad-cli/src/cmds/mod.rs
@@ -37,9 +37,9 @@ pub use self::relay::Relay;
mod reset;
pub use self::reset::Reset;
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", windows))]
mod split_tunnel;
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", windows))]
pub use self::split_tunnel::SplitTunnel;
mod status;
@@ -66,7 +66,7 @@ pub fn get_commands() -> HashMap<&'static str, Box<dyn Command>> {
Box::new(Lan),
Box::new(Relay),
Box::new(Reset),
- #[cfg(target_os = "linux")]
+ #[cfg(any(target_os = "linux", windows))]
Box::new(SplitTunnel),
Box::new(Status),
Box::new(Tunnel),
diff --git a/mullvad-cli/src/cmds/split_tunnel/mod.rs b/mullvad-cli/src/cmds/split_tunnel/mod.rs
index c7c366d6ea..c9e87f5d7c 100644
--- a/mullvad-cli/src/cmds/split_tunnel/mod.rs
+++ b/mullvad-cli/src/cmds/split_tunnel/mod.rs
@@ -2,5 +2,9 @@
#[path = "linux.rs"]
mod imp;
-#[cfg(target_os = "linux")]
+#[cfg(windows)]
+#[path = "windows.rs"]
+mod imp;
+
+#[cfg(any(target_os = "linux", windows))]
pub use imp::*;
diff --git a/mullvad-cli/src/cmds/split_tunnel/windows.rs b/mullvad-cli/src/cmds/split_tunnel/windows.rs
new file mode 100644
index 0000000000..5f6fa8878e
--- /dev/null
+++ b/mullvad-cli/src/cmds/split_tunnel/windows.rs
@@ -0,0 +1,112 @@
+use crate::{new_rpc_client, Command, Result};
+use clap::value_t_or_exit;
+
+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, 'static> {
+ clap::SubCommand::with_name(self.name())
+ .about("Set options for applications to exclude from the tunnel")
+ .setting(clap::AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(create_app_subcommand())
+ .subcommand(
+ clap::SubCommand::with_name("set")
+ .about("Enable or disable split tunnel")
+ .arg(
+ clap::Arg::with_name("policy")
+ .required(true)
+ .possible_values(&["on", "off"]),
+ ),
+ )
+ .subcommand(clap::SubCommand::with_name("get").about("Display the split tunnel status"))
+ }
+
+ async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> {
+ match matches.subcommand() {
+ ("app", Some(matches)) => Self::handle_app_subcommand(matches).await,
+ ("get", _) => self.get().await,
+ ("set", Some(matches)) => {
+ let enabled = value_t_or_exit!(matches.value_of("policy"), String);
+ self.set(enabled == "on").await
+ }
+ _ => {
+ unreachable!("unhandled command");
+ }
+ }
+ }
+}
+
+fn create_app_subcommand() -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name("app")
+ .about("Manage applications to exclude from the tunnel")
+ .setting(clap::AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(clap::SubCommand::with_name("list"))
+ .subcommand(
+ clap::SubCommand::with_name("add").arg(clap::Arg::with_name("path").required(true)),
+ )
+ .subcommand(
+ clap::SubCommand::with_name("remove").arg(clap::Arg::with_name("path").required(true)),
+ )
+ .subcommand(clap::SubCommand::with_name("clear"))
+}
+
+impl SplitTunnel {
+ async fn handle_app_subcommand(matches: &clap::ArgMatches<'_>) -> Result<()> {
+ match matches.subcommand() {
+ ("list", Some(_)) => {
+ let mut paths = new_rpc_client()
+ .await?
+ .get_split_tunnel_apps(())
+ .await?
+ .into_inner();
+
+ println!("Excluded applications:");
+ while let Some(path) = paths.message().await? {
+ println!(" {}", path);
+ }
+
+ Ok(())
+ }
+ ("add", Some(matches)) => {
+ let path = value_t_or_exit!(matches.value_of("path"), String);
+ new_rpc_client().await?.add_split_tunnel_app(path).await?;
+ Ok(())
+ }
+ ("remove", Some(matches)) => {
+ let path = value_t_or_exit!(matches.value_of("path"), String);
+ new_rpc_client()
+ .await?
+ .remove_split_tunnel_app(path)
+ .await?;
+ Ok(())
+ }
+ ("clear", Some(_)) => {
+ new_rpc_client().await?.clear_split_tunnel_apps(()).await?;
+ 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;
+ println!(
+ "Split tunnel status: {}",
+ if enabled { "on" } else { "off" }
+ );
+ Ok(())
+ }
+}