summaryrefslogtreecommitdiffhomepage
path: root/mullvad-cli/src/cmds/obfuscation.rs
blob: 99887db55521bf2e0eb0cab1c65bf9eb3051959a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::{new_rpc_client, Command, Result};

use mullvad_management_interface::{types as grpc_types, ManagementServiceClient};

use mullvad_types::relay_constraints::{ObfuscationSettings, SelectedObfuscation};

use std::convert::TryFrom;

pub struct Obfuscation;

#[mullvad_management_interface::async_trait]
impl Command for Obfuscation {
    fn name(&self) -> &'static str {
        "obfuscation"
    }

    fn clap_subcommand(&self) -> clap::App<'static> {
        clap::App::new(self.name())
            .about("Manage use of obfuscators")
            .setting(clap::AppSettings::SubcommandRequiredElseHelp)
            .subcommand(create_obfuscation_set_subcommand())
            .subcommand(create_obfuscation_get_subcommand())
    }

    async fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
        match matches.subcommand() {
            Some(("set", set_matches)) => Self::handle_set(set_matches).await,
            Some(("get", get_matches)) => Self::handle_get(get_matches).await,
            _ => unreachable!("unhandled command"),
        }
    }
}

impl Obfuscation {
    async fn handle_set(matches: &clap::ArgMatches) -> Result<()> {
        match matches.subcommand() {
            Some(("mode", mode_matches)) => {
                let obfuscator_type = mode_matches.value_of("mode").unwrap();
                let mut rpc = new_rpc_client().await?;
                let mut settings = Self::get_obfuscation_settings(&mut rpc).await?;
                settings.selected_obfuscation = match obfuscator_type {
                    "auto" => SelectedObfuscation::Auto,
                    "off" => SelectedObfuscation::Off,
                    "udp2tcp" => SelectedObfuscation::Udp2Tcp,
                    _ => unreachable!("Unhandled obfuscator mode"),
                };
                Self::set_obfuscation_settings(&mut rpc, &settings).await?;
            }
            Some(("udp2tcp-settings", settings_matches)) => {
                let port: String = settings_matches.value_of_t_or_exit("port");
                let mut rpc = new_rpc_client().await?;
                let mut settings = Self::get_obfuscation_settings(&mut rpc).await?;
                settings.udp2tcp.port = if port == "any" {
                    mullvad_types::relay_constraints::Constraint::Any
                } else {
                    mullvad_types::relay_constraints::Constraint::Only(
                        port.parse::<u16>().expect("Invalid port number"),
                    )
                };
                Self::set_obfuscation_settings(&mut rpc, &settings).await?;
            }
            _ => unreachable!("unhandled command"),
        }
        Ok(())
    }

    async fn handle_get(matches: &clap::ArgMatches) -> Result<()> {
        let mut rpc = new_rpc_client().await?;
        let settings = Self::get_obfuscation_settings(&mut rpc).await?;
        match matches.subcommand() {
            Some(("udp2tcp-settings", _)) => println!("Udp2Tcp: {}", settings.udp2tcp),
            _ => println!("Current settings: {}", settings),
        }
        Ok(())
    }

    async fn get_obfuscation_settings(
        rpc: &mut ManagementServiceClient,
    ) -> Result<ObfuscationSettings> {
        let settings = rpc.get_settings(()).await?.into_inner();

        let obfuscation_settings = ObfuscationSettings::try_from(
            settings
                .obfuscation_settings
                .expect("No obfuscation settings"),
        )
        .expect("failed to parse obfuscation settings");
        Ok(obfuscation_settings)
    }

    async fn set_obfuscation_settings(
        rpc: &mut ManagementServiceClient,
        settings: &ObfuscationSettings,
    ) -> Result<()> {
        let grpc_settings: grpc_types::ObfuscationSettings = settings.into();
        let _ = rpc.set_obfuscation_settings(grpc_settings).await?;
        Ok(())
    }
}

fn create_obfuscation_set_subcommand() -> clap::App<'static> {
    clap::App::new("set")
        .about("Set obfuscation settings")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .subcommand(
            clap::App::new("mode").about("Set obfuscation mode").arg(
                clap::Arg::new("mode")
                    .help("Specifies what kind of obfuscation should be used, if any")
                    .required(true)
                    .index(1)
                    .possible_values(&["auto", "off", "udp2tcp"]),
            ),
        )
        .subcommand(
            clap::App::new("udp2tcp-settings")
                .about("Specifies the config for the udp2tcp obfuscator")
                .setting(clap::AppSettings::ArgRequiredElseHelp)
                .arg(
                    clap::Arg::new("port")
                        .help("TCP port of remote endpoint. Either 'any' or a specific port")
                        .long("port")
                        .takes_value(true),
                ),
        )
}

fn create_obfuscation_get_subcommand() -> clap::App<'static> {
    clap::App::new("get")
        .about("Get obfuscation settings")
        .subcommand(
            clap::App::new("udp2tcp-settings")
                .about("Specifies the config for the udp2tcp obfuscator"),
        )
}