diff options
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid_cli/Cargo.toml | 9 | ||||
| -rw-r--r-- | talpid_cli/src/cli.rs | 84 | ||||
| -rw-r--r-- | talpid_cli/src/main.rs | 83 |
4 files changed, 68 insertions, 110 deletions
diff --git a/Cargo.toml b/Cargo.toml index ebdd8443ac..6c90856996 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["mullvad_daemon", "talpid_openvpn_plugin", "openvpn_ffi", "talpid_ipc"] +members = ["mullvad_daemon", "talpid_openvpn_plugin", "openvpn_ffi", "talpid_ipc", "talpid_cli"] diff --git a/talpid_cli/Cargo.toml b/talpid_cli/Cargo.toml index 8a3f013737..f6b563ae9c 100644 --- a/talpid_cli/Cargo.toml +++ b/talpid_cli/Cargo.toml @@ -4,11 +4,14 @@ version = "0.0.0" authors = ["Linus Färnstrand <linus@mullvad.net>", "Erik Larkö <erik@mullvad.net>"] description = "Run Talpid easily from the command line" +[[bin]] +name = "mullvad" + [dependencies] clap = "2.20" error-chain = "0.10" log = "0.3" env_logger = "0.4" - -[dependencies.talpid_core] -path = "../talpid_core" +talpid_ipc = { path = "../talpid_ipc" } +serde = "1.0" +serde_json = "1.0" diff --git a/talpid_cli/src/cli.rs b/talpid_cli/src/cli.rs index b61c4112b5..be2f4c3ef4 100644 --- a/talpid_cli/src/cli.rs +++ b/talpid_cli/src/cli.rs @@ -1,37 +1,6 @@ -use clap::{App, Arg, ArgMatches}; -use std::path::PathBuf; +use clap::{App, Arg, ArgMatches, SubCommand, AppSettings}; -use talpid_core::net::RemoteAddr; - -#[cfg(all(unix, not(target_os="macos")))] -const DEFAULT_PLUGIN_PATH: &'static str = "./target/debug/libtalpid_openvpn_plugin.so"; -#[cfg(target_os="macos")] -const DEFAULT_PLUGIN_PATH: &'static str = "./target/debug/libtalpid_openvpn_plugin.dylib"; -#[cfg(windows)] -const DEFAULT_PLUGIN_PATH: &'static str = "./target/debug/libtalpid_openvpn_plugin.dll"; - - -pub struct Args { - pub binary: String, - pub plugin_path: PathBuf, - pub config: PathBuf, - pub remotes: Vec<RemoteAddr>, - pub verbosity: u64, -} - -pub fn parse_args_or_exit() -> Args { - let matches = get_matches(); - let remotes = values_t!(matches.values_of("remotes"), RemoteAddr).unwrap_or_else(|e| e.exit()); - Args { - binary: matches.value_of("openvpn").unwrap().to_owned(), - plugin_path: PathBuf::from(matches.value_of("plugin").unwrap()), - config: PathBuf::from(matches.value_of("config").unwrap()), - remotes: remotes, - verbosity: matches.occurrences_of("verbose"), - } -} - -fn get_matches() -> ArgMatches<'static> { +pub fn get_matches() -> ArgMatches<'static> { let app = create_app(); app.clone().get_matches() } @@ -41,42 +10,15 @@ fn create_app() -> App<'static, 'static> { .version(crate_version!()) .author(crate_authors!()) .about(crate_description!()) - .arg( - Arg::with_name("openvpn") - .long("openvpn") - .help("Specify what OpenVPN binary to run") - .default_value("/usr/sbin/openvpn"), - ) - .arg( - Arg::with_name("config") - .short("c") - .long("config") - .help("Specify what config file to start OpenVPN with") - .default_value("./openvpn.conf"), - ) - .arg( - Arg::with_name("remotes") - .short("r") - .long("remotes") - .help( - "Configure what remote(s) to connect to. Accepts anything OpenVPN can use. \ - Format: <address>:<port>", - ) - .takes_value(true) - .multiple(true) - .required(true), - ) - .arg( - Arg::with_name("plugin") - .long("plugin") - .help("Path to talpid plugin") - .default_value(DEFAULT_PLUGIN_PATH), - ) - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .multiple(true) - .help("Sets the level of verbosity"), - ) + .setting(AppSettings::SubcommandRequired) + .subcommand(SubCommand::with_name("account") + .about("Control and display information about the configured Mullvad account") + .setting(AppSettings::SubcommandRequired) + .subcommand(SubCommand::with_name("set") + .about("Change the Mullvad account") + .arg(Arg::with_name("token") + .help("The Mullvad account token to configure the daemon with") + .required(true))) + .subcommand(SubCommand::with_name("get") + .about("Display information about the currently configured account"))) } diff --git a/talpid_cli/src/main.rs b/talpid_cli/src/main.rs index 2f1e5c36dc..0d87173418 100644 --- a/talpid_cli/src/main.rs +++ b/talpid_cli/src/main.rs @@ -1,19 +1,19 @@ // `error_chain!` can recurse deeply #![recursion_limit = "1024"] -extern crate talpid_core; +extern crate talpid_ipc; #[macro_use] extern crate clap; #[macro_use] extern crate error_chain; +#[macro_use] extern crate log; extern crate env_logger; +extern crate serde; +extern crate serde_json; -use std::sync::Mutex; -use std::sync::mpsc::{self, Receiver}; -use talpid_core::net::RemoteAddr; - -use talpid_core::tunnel::{TunnelEvent, TunnelMonitor}; +use std::fs::File; +use std::io::Read; mod cli; @@ -23,40 +23,53 @@ error_chain!{} quick_main!(run); fn run() -> Result<()> { - init_logger()?; - let args = cli::parse_args_or_exit(); - main_loop(&args.remotes) -} + env_logger::init().chain_err(|| "Failed to bootstrap logging system")?; -pub fn init_logger() -> Result<()> { - env_logger::init().chain_err(|| "Failed to bootstrap logging system") + let matches = cli::get_matches(); + if let Some(matches) = matches.subcommand_matches("account") { + cmd_account(matches) + } else { + unreachable!("No subcommand matches.") + } } -fn main_loop(remotes: &[RemoteAddr]) -> Result<()> { - let mut remotes_iter = remotes.iter().cloned().cycle(); - let (monitor, rx) = create_tunnel_monitor()?; - loop { - monitor.start(remotes_iter.next().unwrap()).chain_err(|| "Unable to start OpenVPN")?; - while let Ok(msg) = rx.recv() { - match msg { - TunnelEvent::Shutdown => { - println!("Monitored process exited"); - break; - } - TunnelEvent::Up => println!("Tunnel UP"), - TunnelEvent::Down => println!("Tunnel DOWN"), - } +fn cmd_account(matches: &clap::ArgMatches) -> Result<()> { + if let Some(matches) = matches.subcommand_matches("set") { + let token = matches.value_of("token").unwrap(); + call_rpc("set_account", &[token]).map( + |_| { + println!("Mullvad account {} set", token); + }, + ) + } else if let Some(_matches) = matches.subcommand_matches("get") { + match call_rpc("get_account", &[] as &[u8; 0])? { + serde_json::Value::String(token) => println!("Mullvad account: {:?}", token), + serde_json::Value::Null => println!("No account configured"), + _ => bail!("Unable to fetch account token"), } - std::thread::sleep(std::time::Duration::from_millis(500)); + Ok(()) + } else { + unreachable!("No account command given"); } } -fn create_tunnel_monitor() -> Result<(TunnelMonitor, Receiver<TunnelEvent>)> { - let (event_tx, event_rx) = mpsc::channel(); - let event_tx_mutex = Mutex::new(event_tx); - let on_event = move |event: TunnelEvent| { - event_tx_mutex.lock().unwrap().send(event).expect("Unable to send on tx_lock"); - }; - let monitor = TunnelMonitor::new(on_event).chain_err(|| "Unable to start OpenVPN monitor")?; - Ok((monitor, event_rx)) +fn call_rpc<T>(method: &str, args: &T) -> Result<serde_json::Value> + where T: serde::Serialize +{ + let address = read_rpc_address()?; + info!("Using RPC address {}", address); + let mut rpc_client = talpid_ipc::WsIpcClient::new(address) + .chain_err(|| "Unable to create RPC client")?; + rpc_client.call(method, args).chain_err(|| "Unable to call RPC method") +} + +fn read_rpc_address() -> Result<String> { + for path in &["./.mullvad_rpc_address", "../.mullvad_rpc_address"] { + debug!("Trying to read RPC address at {}", path); + let mut address = String::new(); + if let Ok(_) = File::open(path).and_then(|mut file| file.read_to_string(&mut address)) { + return Ok(address); + } + } + bail!("Unable to read RPC address"); } |
