diff options
| -rw-r--r-- | Cargo.lock | 13 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | openvpn-ffi/Cargo.toml | 13 | ||||
| -rw-r--r-- | openvpn-ffi/src/lib.rs | 151 | ||||
| -rw-r--r-- | openvpn-ffi/src/parse.rs | 146 | ||||
| -rw-r--r-- | openvpn-ffi/src/structs.rs | 49 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/process/openvpn.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/openvpn.rs | 18 | ||||
| -rw-r--r-- | talpid-openvpn-plugin/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-openvpn-plugin/src/lib.rs | 131 | ||||
| -rw-r--r-- | talpid-openvpn-plugin/src/processing.rs | 17 |
14 files changed, 59 insertions, 490 deletions
diff --git a/Cargo.lock b/Cargo.lock index 3903f4a902..b4c1afb5e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openvpn-ffi 0.1.0", + "openvpn-plugin 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-ipc 0.1.0", ] @@ -500,11 +500,11 @@ dependencies = [ ] [[package]] -name = "openvpn-ffi" -version = "0.1.0" +name = "openvpn-plugin" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "assert_matches 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -723,7 +723,7 @@ dependencies = [ "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mktemp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openvpn-ffi 0.1.0", + "openvpn-plugin 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-ipc 0.1.0", ] @@ -998,6 +998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" "checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" +"checksum openvpn-plugin 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99c05a2229a24799412627dd22730729796aca97405dedc297a622536f37fb3b" "checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "37f364e2ce5efa24c7d0b6646d5bb61145551a0112f107ffd7499f1a3e322fbd" diff --git a/Cargo.toml b/Cargo.toml index 7c598c504c..a1d53676c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,4 @@ members = [ "talpid-openvpn-plugin", "talpid-core", "talpid-ipc", - "openvpn-ffi", ] diff --git a/openvpn-ffi/Cargo.toml b/openvpn-ffi/Cargo.toml deleted file mode 100644 index fd739707f0..0000000000 --- a/openvpn-ffi/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "openvpn-ffi" -version = "0.1.0" -authors = ["Linus Färnstrand <linus@mullvad.net>", "Erik Larkö <erik@mullvad.net>"] -description = "Constants, enums and structs for interfacing with OpenVPN" - -[dependencies] -error-chain = "0.10" -serde = "1.0" -serde_derive = "1.0" - -[dev-dependencies] -assert_matches = "1.0" diff --git a/openvpn-ffi/src/lib.rs b/openvpn-ffi/src/lib.rs deleted file mode 100644 index 934eb091df..0000000000 --- a/openvpn-ffi/src/lib.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Constants for OpenVPN. Taken from include/openvpn-plugin.h in the OpenVPN repository: -//! https://github.com/OpenVPN/openvpn/blob/master/include/openvpn-plugin.h.in - -#[macro_use] -extern crate error_chain; - -#[macro_use] -extern crate serde_derive; - -#[cfg(test)] -#[macro_use] -extern crate assert_matches; - - -use std::collections::HashMap; -use std::os::raw::c_int; - -mod structs; -pub use structs::*; - -pub mod parse; - -error_chain!{ - errors { - InvalidEnumVariant(i: c_int) { - description("Integer does not match any enum variant") - display("{} is not a valid OPENVPN_PLUGIN_* constant", i) - } - } -} - - -/// Type definition for environment variables from OpenVPN -pub type OpenVpnEnv = HashMap<String, String>; - - -// Return values. Returned from the plugin to OpenVPN to indicate success or failure. Can also -// Accept (success) or decline (error) an operation, such as incoming client connection attempt. -pub const OPENVPN_PLUGIN_FUNC_SUCCESS: c_int = 0; -pub const OPENVPN_PLUGIN_FUNC_ERROR: c_int = 1; -pub const OPENVPN_PLUGIN_FUNC_DEFERRED: c_int = 2; - - -/// Enum whose variants correspond to the `OPENVPN_PLUGIN_*` event constants. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub enum OpenVpnPluginEvent { - Up = 0, - Down = 1, - RouteUp = 2, - IpChange = 3, - TlsVerify = 4, - AuthUserPassVerify = 5, - ClientConnect = 6, - ClientDisconnect = 7, - LearnAddress = 8, - ClientConnectV2 = 9, - TlsFinal = 10, - EnablePf = 11, - RoutePredown = 12, - N = 13, -} - -impl OpenVpnPluginEvent { - /// Tries to parse an integer from C into a variant of `OpenVpnPluginEvent`. - pub fn from_int(i: c_int) -> Result<OpenVpnPluginEvent> { - if i >= OpenVpnPluginEvent::Up as c_int && i <= OpenVpnPluginEvent::N as c_int { - Ok(unsafe { ::std::mem::transmute_copy::<c_int, OpenVpnPluginEvent>(&i) },) - } else { - bail!(ErrorKind::InvalidEnumVariant(i)); - } - } -} - -/// Translates a collection of `OpenVpnPluginEvent` instances into a bitmask in the format OpenVPN -/// expects it. -pub fn events_to_bitmask(events: &[OpenVpnPluginEvent]) -> c_int { - let mut bitmask: c_int = 0; - for event in events { - bitmask |= 1 << (*event as i32); - } - bitmask -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn from_int_first() { - let result = OpenVpnPluginEvent::from_int(0); - assert_matches!(result, Ok(OpenVpnPluginEvent::Up)); - } - - #[test] - fn from_int_last() { - let result = OpenVpnPluginEvent::from_int(13); - assert_matches!(result, Ok(OpenVpnPluginEvent::N)); - } - - #[test] - fn from_int_all_valid() { - for i in 0..13 { - if OpenVpnPluginEvent::from_int(i).is_err() { - panic!("{} not covered", i); - } - } - } - - #[test] - fn from_int_negative() { - let result = OpenVpnPluginEvent::from_int(-5); - assert_matches!(result, Err(Error(ErrorKind::InvalidEnumVariant(-5), _))); - } - - #[test] - fn from_int_invalid() { - let result = OpenVpnPluginEvent::from_int(14); - assert_matches!(result, Err(Error(ErrorKind::InvalidEnumVariant(14), _))); - } - - #[test] - fn event_enum_to_str() { - let result = format!("{:?}", OpenVpnPluginEvent::Up); - assert_eq!("Up", result); - } - - #[test] - fn events_to_bitmask_no_events() { - let result = events_to_bitmask(&[]); - assert_eq!(0, result); - } - - #[test] - fn events_to_bitmask_one_event() { - let result = events_to_bitmask(&[OpenVpnPluginEvent::Up]); - assert_eq!(0b1, result); - } - - #[test] - fn events_to_bitmask_another_event() { - let result = events_to_bitmask(&[OpenVpnPluginEvent::RouteUp]); - assert_eq!(0b100, result); - } - - #[test] - fn events_to_bitmask_many_events() { - let result = events_to_bitmask(&[OpenVpnPluginEvent::RouteUp, OpenVpnPluginEvent::N]); - assert_eq!((1 << 13) + (1 << 2), result); - } -} diff --git a/openvpn-ffi/src/parse.rs b/openvpn-ffi/src/parse.rs deleted file mode 100644 index 6d0c42c06f..0000000000 --- a/openvpn-ffi/src/parse.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::collections::HashMap; -use std::ffi::CStr; -use std::os::raw::c_char; - -error_chain!{ - errors { - Null { - description("Input is null pointer") - } - NoEqual(s: String) { - description("No equal sign in string") - display("No equal sign in \"{}\"", s) - } - } - foreign_links { - InvalidContent(::std::str::Utf8Error); - } -} - - -/// Parses a null-terminated C string array into a Vec<String> for safe usage. -/// -/// Returns an Err if given a null pointer or if a string is not valid utf-8. -/// -/// # Segfaults -/// -/// Can cause the program to crash if the pointer array starting at `ptr` is not correctly null -/// terminated. Likewise, if any string pointed to is not properly null-terminated it may crash. -pub unsafe fn string_array(mut ptr: *const *const c_char) -> Result<Vec<String>> { - if ptr.is_null() { - bail!(ErrorKind::Null); - } else { - let mut strings = Vec::new(); - while !(*ptr).is_null() { - let cstr = CStr::from_ptr(*ptr); - strings.push(cstr.to_str()?.to_owned()); - ptr = ptr.offset(1); - } - Ok(strings) - } -} - - -/// Parses a null-terminated array of C strings with "=" delimiters into a key-value map. -/// -/// The input environment has to contain null-terminated strings containing at least -/// one equal sign ("="). Every string is split at the first equal sign and added to the map with -/// the first part being the key and the second the value. -/// -/// If multiple entries have the same key, the last one will be in the result map. -/// -/// # Segfaults -/// -/// Uses `string_array` internally and will segfault for the same reasons as that function. -pub unsafe fn env(envptr: *const *const c_char) -> Result<::OpenVpnEnv> { - let mut map = HashMap::new(); - for string in string_array(envptr)? { - let mut iter = string.splitn(2, '='); - let key = iter.next().unwrap(); - let value = iter.next().ok_or_else(|| Error::from(ErrorKind::NoEqual(string.clone())))?; - map.insert(key.to_owned(), value.to_owned()); - } - Ok(map) -} - - -#[cfg(test)] -mod tests { - use super::*; - use std::os::raw::c_char; - use std::ptr; - - #[test] - fn string_array_null() { - let result = unsafe { string_array(ptr::null()) }; - assert_matches!(result, Err(Error(ErrorKind::Null, _))); - } - - #[test] - fn string_array_empty() { - let ptr_arr = [ptr::null()]; - let result = unsafe { string_array(&ptr_arr as *const *const c_char).unwrap() }; - assert!(result.is_empty()); - } - - #[test] - fn string_array_no_space_trim() { - let test_str = " foobar \0"; - let ptr_arr = [test_str as *const _ as *const c_char, ptr::null()]; - let result = unsafe { string_array(&ptr_arr as *const *const c_char).unwrap() }; - assert_eq!([" foobar "], &result[..]); - } - - #[test] - fn string_array_two_strings() { - let test_str1 = "foobar\0"; - let test_str2 = "barbaz\0"; - let ptr_arr = [ - test_str1 as *const _ as *const c_char, - test_str2 as *const _ as *const c_char, - ptr::null(), - ]; - let result = unsafe { string_array(&ptr_arr as *const *const c_char).unwrap() }; - assert_eq!(["foobar", "barbaz"], &result[..]); - } - - #[test] - fn env_one_value() { - let test_str = "var_a=value_b\0"; - let ptr_arr = [test_str as *const _ as *const c_char, ptr::null()]; - let result = unsafe { env(&ptr_arr as *const *const c_char).unwrap() }; - assert_eq!(1, result.len()); - assert_eq!(Some("value_b"), result.get("var_a").map(|s| &s[..])); - } - - #[test] - fn env_no_equal() { - let test_str = "foobar\0"; - let ptr_arr = [test_str as *const _ as *const c_char, ptr::null()]; - let result = unsafe { env(&ptr_arr as *const *const c_char) }; - assert_matches!(result, Err(Error(ErrorKind::NoEqual(_), _))); - } - - #[test] - fn env_double_equal() { - let test_str = "foo=bar=baz\0"; - let ptr_arr = [test_str as *const _ as *const c_char, ptr::null()]; - let env = unsafe { env(&ptr_arr as *const *const c_char).unwrap() }; - assert_eq!(1, env.len()); - assert_eq!(Some("bar=baz"), env.get("foo").map(|s| &s[..])); - } - - #[test] - fn env_two_same_key() { - let test_str1 = "foo=123\0"; - let test_str2 = "foo=abc\0"; - let ptr_arr = [ - test_str1 as *const _ as *const c_char, - test_str2 as *const _ as *const c_char, - ptr::null(), - ]; - let env = unsafe { env(&ptr_arr as *const *const c_char).unwrap() }; - assert_eq!(1, env.len()); - assert_eq!(Some("abc"), env.get("foo").map(|s| &s[..])); - } -} diff --git a/openvpn-ffi/src/structs.rs b/openvpn-ffi/src/structs.rs deleted file mode 100644 index b80f7ae2a2..0000000000 --- a/openvpn-ffi/src/structs.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::os::raw::{c_char, c_int, c_uint, c_void}; - -/// Struct sent to `openvpn_plugin_open_v3` containing input values. -#[repr(C)] -pub struct openvpn_plugin_args_open_in { - type_mask: c_int, - pub argv: *const *const c_char, - envp: *const *const c_char, - callbacks: *const c_void, - ssl_api: ovpnSSLAPI, - ovpn_version: *const c_char, - ovpn_version_major: c_uint, - ovpn_version_minor: c_uint, - ovpn_version_patch: *const c_char, -} - -#[allow(dead_code)] -#[repr(C)] -enum ovpnSSLAPI { - None, - OpenSsl, - MbedTls, -} - -/// Struct used for returning values from `openvpn_plugin_open_v3` to OpenVPN. -#[repr(C)] -pub struct openvpn_plugin_args_open_return { - pub type_mask: c_int, - pub handle: *const c_void, - return_list: *const c_void, -} - -/// Struct sent to `openvpn_plugin_func_v3` containing input values. -#[repr(C)] -pub struct openvpn_plugin_args_func_in { - pub event_type: c_int, - argv: *const *const c_char, - pub envp: *const *const c_char, - pub handle: *const c_void, - per_client_context: *const c_void, - current_cert_depth: c_int, - current_cert: *const c_void, -} - -/// Struct used for returning values from `openvpn_plugin_func_v3` to OpenVPN. -#[repr(C)] -pub struct openvpn_plugin_args_func_return { - return_list: *const c_void, -} diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 2be5457e26..96c30924e2 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -13,7 +13,7 @@ lazy_static = "0.2" log = "0.3" mktemp = "0.3" -openvpn-ffi = { path = "../openvpn-ffi" } +openvpn-plugin = { version = "0.2", features = ["serialize"] } talpid-ipc = { path = "../talpid-ipc" } [target.'cfg(unix)'.dependencies] diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 1fc92f8fe4..29ab0377e5 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -21,7 +21,7 @@ extern crate jsonrpc_core; extern crate jsonrpc_macros; extern crate talpid_ipc; -extern crate openvpn_ffi; +extern crate openvpn_plugin; /// Working with processes. pub mod process; diff --git a/talpid-core/src/process/openvpn.rs b/talpid-core/src/process/openvpn.rs index ea66ef894c..6b671b767c 100644 --- a/talpid-core/src/process/openvpn.rs +++ b/talpid-core/src/process/openvpn.rs @@ -1,5 +1,3 @@ -extern crate openvpn_ffi; - use duct; use net; diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index b05f1283f3..3835e26632 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -1,6 +1,6 @@ use mktemp; use net; -use openvpn_ffi::OpenVpnPluginEvent; +use openvpn_plugin::types::OpenVpnPluginEvent; use process::openvpn::OpenVpnCommand; use std::fs; use std::io::{self, Write}; diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs index 08c2c14a32..f545a1d4d1 100644 --- a/talpid-core/src/tunnel/openvpn.rs +++ b/talpid-core/src/tunnel/openvpn.rs @@ -1,8 +1,9 @@ use duct; use jsonrpc_core::{Error, IoHandler}; -use openvpn_ffi::{OpenVpnEnv, OpenVpnPluginEvent}; +use openvpn_plugin::types::OpenVpnPluginEvent; use process::openvpn::OpenVpnCommand; +use std::collections::HashMap; use std::io; use std::path::Path; use std::result::Result as StdResult; @@ -47,7 +48,7 @@ impl OpenVpnMonitor { /// Creates a new `OpenVpnMonitor` with the given listener and using the plugin at the given /// path. pub fn new<L, P>(mut cmd: OpenVpnCommand, on_event: L, plugin_path: P) -> Result<Self> - where L: Fn(OpenVpnPluginEvent, OpenVpnEnv) + Send + Sync + 'static, + where L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static, P: AsRef<Path> { let event_dispatcher = OpenVpnEventDispatcher::start(on_event) @@ -180,7 +181,7 @@ pub struct OpenVpnEventDispatcher { impl OpenVpnEventDispatcher { /// Construct and start the IPC server with the given event listener callback. pub fn start<L>(on_event: L) -> talpid_ipc::Result<Self> - where L: Fn(OpenVpnPluginEvent, OpenVpnEnv) + Send + Sync + 'static + where L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static { let rpc = OpenVpnEventApiImpl { on_event }; let mut io = IoHandler::new(); @@ -215,7 +216,7 @@ mod api { #[rpc(name = "openvpn_event")] fn openvpn_event(&self, OpenVpnPluginEvent, - OpenVpnEnv) + HashMap<String, String>) -> StdResult<(), Error>; } } @@ -223,15 +224,18 @@ mod api { use self::api::*; struct OpenVpnEventApiImpl<L> - where L: Fn(OpenVpnPluginEvent, OpenVpnEnv) + Send + Sync + 'static + where L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static { on_event: L, } impl<L> OpenVpnEventApi for OpenVpnEventApiImpl<L> - where L: Fn(OpenVpnPluginEvent, OpenVpnEnv) + Send + Sync + 'static + where L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static { - fn openvpn_event(&self, event: OpenVpnPluginEvent, env: OpenVpnEnv) -> StdResult<(), Error> { + fn openvpn_event(&self, + event: OpenVpnPluginEvent, + env: HashMap<String, String>) + -> StdResult<(), Error> { debug!("OpenVPN event {:?}", event); (self.on_event)(event, env); Ok(()) diff --git a/talpid-openvpn-plugin/Cargo.toml b/talpid-openvpn-plugin/Cargo.toml index c2ae39430c..e0b4ddec77 100644 --- a/talpid-openvpn-plugin/Cargo.toml +++ b/talpid-openvpn-plugin/Cargo.toml @@ -12,5 +12,5 @@ error-chain = "0.10" log = "0.3" env_logger = "0.4" +openvpn-plugin = { version = "0.2", features = ["serialize", "log"] } talpid-ipc = { path = "../talpid-ipc" } -openvpn-ffi = { path = "../openvpn-ffi" } diff --git a/talpid-openvpn-plugin/src/lib.rs b/talpid-openvpn-plugin/src/lib.rs index 55102d111c..5bb8bece64 100644 --- a/talpid-openvpn-plugin/src/lib.rs +++ b/talpid-openvpn-plugin/src/lib.rs @@ -4,16 +4,15 @@ extern crate error_chain; extern crate log; extern crate env_logger; -extern crate openvpn_ffi; +#[macro_use] +extern crate openvpn_plugin; extern crate talpid_ipc; -use std::os::raw::{c_int, c_void}; +use openvpn_plugin::types::{EventResult, OpenVpnPluginEvent}; +use std::collections::HashMap; +use std::ffi::CString; mod processing; - -use openvpn_ffi::{OPENVPN_PLUGIN_FUNC_ERROR, OPENVPN_PLUGIN_FUNC_SUCCESS, OpenVpnPluginEvent, - openvpn_plugin_args_func_in, openvpn_plugin_args_func_return, - openvpn_plugin_args_open_in, openvpn_plugin_args_open_return}; use processing::EventProcessor; @@ -43,117 +42,51 @@ error_chain!{ pub static INTERESTING_EVENTS: &'static [OpenVpnPluginEvent] = &[OpenVpnPluginEvent::Up, OpenVpnPluginEvent::RoutePredown]; +openvpn_plugin!( + ::openvpn_open, + ::openvpn_close, + ::openvpn_event, + ::EventProcessor +); -/// Called by OpenVPN when the plugin is first loaded. -/// Used to register which events the plugin wants to listen to (`args.type_mask`). Can also set an -/// arbitrary pointer inside `args.handle` that will then be passed to all subsequent calls to the -/// plugin. -#[no_mangle] -pub extern "C" fn openvpn_plugin_open_v3(_version: c_int, - args: *const openvpn_plugin_args_open_in, - retptr: *mut openvpn_plugin_args_open_return) - -> c_int { - if init_logger().is_err() { - return OPENVPN_PLUGIN_FUNC_ERROR; - } - match openvpn_plugin_open_v3_internal(args, retptr) { - Ok(_) => OPENVPN_PLUGIN_FUNC_SUCCESS, - Err(e) => { - log_error("Unable to initialize plugin", &e); - OPENVPN_PLUGIN_FUNC_ERROR - } - } -} - -fn openvpn_plugin_open_v3_internal(args: *const openvpn_plugin_args_open_in, - retptr: *mut openvpn_plugin_args_open_return) - -> Result<()> { +fn openvpn_open(args: &[CString], + _env: &HashMap<CString, CString>) + -> Result<(Vec<OpenVpnPluginEvent>, EventProcessor)> { + env_logger::init().chain_err(|| "Failed to bootstrap logging system")?; debug!("Initializing plugin"); + let core_server_id = parse_args(args)?; + info!("Connecting back to talpid core at {}", core_server_id); let processor = EventProcessor::new(core_server_id).chain_err(|| ErrorKind::InitHandleFailed)?; - unsafe { - (*retptr).type_mask = openvpn_ffi::events_to_bitmask(INTERESTING_EVENTS); - // Converting the handle into a raw pointer will make it escape Rust deallocation. See - // `openvpn_plugin_close_v1` for deallocation. - (*retptr).handle = Box::into_raw(Box::new(processor)) as *const c_void; - } - Ok(()) + + Ok((INTERESTING_EVENTS.to_vec(), processor)) } -fn parse_args(args: *const openvpn_plugin_args_open_in) -> Result<talpid_ipc::IpcServerId> { - let mut args_iter = unsafe { openvpn_ffi::parse::string_array((*args).argv) } +fn parse_args(args: &[CString]) -> Result<talpid_ipc::IpcServerId> { + let mut args_iter = openvpn_plugin::ffi::parse::string_array_utf8(args) .chain_err(|| ErrorKind::ParseArgsFailed)? .into_iter(); let _plugin_path = args_iter.next(); - let core_server_id: String = args_iter.next() + let core_server_id: talpid_ipc::IpcServerId = args_iter.next() .ok_or_else(|| ErrorKind::Msg("No core server id given as first argument".to_owned()))?; Ok(core_server_id) } -/// Called by OpenVPN just before the plugin is unloaded. Should correctly close the plugin and -/// deallocate any `handle` initialized by the plugin in `openvpn_plugin_open_v3` -#[no_mangle] -pub extern "C" fn openvpn_plugin_close_v1(handle: *const c_void) { +fn openvpn_close(_handle: EventProcessor) { debug!("Unloading plugin"); - // IMPORTANT: Bring the handle object back from a raw pointer. This will cause the handle - // object to be properly deallocated right here. - let _ = unsafe { Box::from_raw(handle as *mut EventProcessor) }; } - -/// Called by OpenVPN for each `OPENVPN_PLUGIN_*` event that it registered for in -/// `openvpn_plugin_open_v3` -#[no_mangle] -pub extern "C" fn openvpn_plugin_func_v3(_version: c_int, - args: *const openvpn_plugin_args_func_in, - _retptr: *const openvpn_plugin_args_func_return) - -> c_int { - match openvpn_plugin_func_v3_internal(args) { - Ok(_) => OPENVPN_PLUGIN_FUNC_SUCCESS, - Err(e) => { - log_error("Error while processing event", &e); - OPENVPN_PLUGIN_FUNC_ERROR - } - } -} - -fn openvpn_plugin_func_v3_internal(args: *const openvpn_plugin_args_func_in) -> Result<()> { - let event_type = unsafe { (*args).event_type }; - let event = OpenVpnPluginEvent::from_int(event_type).chain_err(|| ErrorKind::InvalidEventType)?; +fn openvpn_event(event: OpenVpnPluginEvent, + _args: &[CString], + env: &HashMap<CString, CString>, + handle: &mut EventProcessor) + -> Result<EventResult> { debug!("Received event: {:?}", event); - let env = unsafe { openvpn_ffi::parse::env((*args).envp) } - .chain_err(|| ErrorKind::ParseEnvFailed)?; - - let mut handle = unsafe { Box::from_raw((*args).handle as *mut EventProcessor) }; - handle.process_event(event, env).chain_err(|| ErrorKind::EventProcessingFailed)?; - // Convert the handle back to a raw pointer to not deallocate it when we return. - Box::into_raw(handle); - - Ok(()) -} + let parsed_env = openvpn_plugin::ffi::parse::env_utf8(env) + .chain_err(|| ErrorKind::ParseEnvFailed)?; - -pub fn init_logger() -> ::std::result::Result<(), ()> { - env_logger::init().or_else( - |e| { - use std::io::Write; - let mut stderr = ::std::io::stderr(); - writeln!(&mut stderr, "Unable to initialize logging: {}", e) - .expect("Unable to write to stderr"); - Err(()) - }, - ) -} - -pub fn log_error(msg: &str, error: &Error) { - error!("{}", msg); - for e in error.iter() { - error!("caused by: {}", e); - } - // When running with RUST_BACKTRACE=1, print backtrace. - if let Some(backtrace) = error.backtrace() { - error!("backtrace: {:?}", backtrace); - } + handle.process_event(event, parsed_env).chain_err(|| ErrorKind::EventProcessingFailed)?; + Ok(EventResult::Success) } diff --git a/talpid-openvpn-plugin/src/processing.rs b/talpid-openvpn-plugin/src/processing.rs index e33097c633..5f3c8e4afd 100644 --- a/talpid-openvpn-plugin/src/processing.rs +++ b/talpid-openvpn-plugin/src/processing.rs @@ -1,5 +1,5 @@ -use openvpn_ffi; - +use openvpn_plugin; +use std::collections::HashMap; use talpid_ipc::{IpcServerId, WsIpcClient}; error_chain! { @@ -18,14 +18,14 @@ pub struct EventProcessor { impl EventProcessor { pub fn new(server_id: IpcServerId) -> Result<EventProcessor> { - debug!("Creating EventProcessor"); + trace!("Creating EventProcessor"); let ipc_client = WsIpcClient::new(server_id).chain_err(|| "Unable to create IPC client")?; Ok(EventProcessor { ipc_client }) } pub fn process_event(&mut self, - event: openvpn_ffi::OpenVpnPluginEvent, - env: openvpn_ffi::OpenVpnEnv) + event: openvpn_plugin::types::OpenVpnPluginEvent, + env: HashMap<String, String>) -> Result<()> { trace!("Processing \"{:?}\" event", event); self.ipc_client @@ -34,10 +34,3 @@ impl EventProcessor { .chain_err(|| ErrorKind::IpcSendingError) } } - -impl Drop for EventProcessor { - fn drop(&mut self) { - // TODO(linus): If we need, this is where we send some shutdown event or similar to core. - debug!("Dropping EventProcessor"); - } -} |
