diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-02-28 15:44:11 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-02-28 15:44:11 +0100 |
| commit | 0fdc6ef08987eb237aba81aee589b35fd8efbb2b (patch) | |
| tree | c0da9e552109353a67193c949bbd8c2b8f8d2d68 /talpid_openvpn_plugin | |
| parent | 4ce365c683dd5ee2ae084db6f1e7bd30fc0398ef (diff) | |
| parent | 40f47e0ecf10c60687edbdcc5e2ad3999547ea74 (diff) | |
| download | mullvadvpn-0fdc6ef08987eb237aba81aee589b35fd8efbb2b.tar.xz mullvadvpn-0fdc6ef08987eb237aba81aee589b35fd8efbb2b.zip | |
Merge branch 'event-enum'
Diffstat (limited to 'talpid_openvpn_plugin')
| -rw-r--r-- | talpid_openvpn_plugin/src/ffi/consts.rs | 109 | ||||
| -rw-r--r-- | talpid_openvpn_plugin/src/ffi/mod.rs | 86 |
2 files changed, 139 insertions, 56 deletions
diff --git a/talpid_openvpn_plugin/src/ffi/consts.rs b/talpid_openvpn_plugin/src/ffi/consts.rs index ca82606751..81fe134b9e 100644 --- a/talpid_openvpn_plugin/src/ffi/consts.rs +++ b/talpid_openvpn_plugin/src/ffi/consts.rs @@ -1,50 +1,42 @@ /// 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 -use std::collections::HashMap; use std::os::raw::c_int; +error_chain!{ + errors { + InvalidEnumVariant { + description("Integer does not match any enum variant") + } + } +} -// All types of events that a plugin can receive from OpenVPN. -pub const OPENVPN_PLUGIN_UP: c_int = 0; -pub const OPENVPN_PLUGIN_DOWN: c_int = 1; -pub const OPENVPN_PLUGIN_ROUTE_UP: c_int = 2; -pub const OPENVPN_PLUGIN_IPCHANGE: c_int = 3; -pub const OPENVPN_PLUGIN_TLS_VERIFY: c_int = 4; -pub const OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: c_int = 5; -pub const OPENVPN_PLUGIN_CLIENT_CONNECT: c_int = 6; -pub const OPENVPN_PLUGIN_CLIENT_DISCONNECT: c_int = 7; -pub const OPENVPN_PLUGIN_LEARN_ADDRESS: c_int = 8; -pub const OPENVPN_PLUGIN_CLIENT_CONNECT_V2: c_int = 9; -pub const OPENVPN_PLUGIN_TLS_FINAL: c_int = 10; -pub const OPENVPN_PLUGIN_ENABLE_PF: c_int = 11; -pub const OPENVPN_PLUGIN_ROUTE_PREDOWN: c_int = 12; -pub const OPENVPN_PLUGIN_N: c_int = 13; - -lazy_static! { - pub static ref PLUGIN_EVENT_NAMES: HashMap<c_int, &'static str> = { - let mut map = HashMap::new(); - map.insert(OPENVPN_PLUGIN_UP, "PLUGIN_UP"); - map.insert(OPENVPN_PLUGIN_DOWN, "PLUGIN_DOWN"); - map.insert(OPENVPN_PLUGIN_ROUTE_UP, "PLUGIN_ROUTE_UP"); - map.insert(OPENVPN_PLUGIN_IPCHANGE, "PLUGIN_IPCHANGE"); - map.insert(OPENVPN_PLUGIN_TLS_VERIFY, "PLUGIN_TLS_VERIFY"); - map.insert(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, "PLUGIN_AUTH_USER_PASS_VERIFY"); - map.insert(OPENVPN_PLUGIN_CLIENT_CONNECT, "PLUGIN_CLIENT_CONNECT"); - map.insert(OPENVPN_PLUGIN_CLIENT_DISCONNECT, "PLUGIN_CLIENT_DISCONNECT"); - map.insert(OPENVPN_PLUGIN_LEARN_ADDRESS, "PLUGIN_LEARN_ADDRESS"); - map.insert(OPENVPN_PLUGIN_CLIENT_CONNECT_V2, "PLUGIN_CLIENT_CONNECT_V2"); - map.insert(OPENVPN_PLUGIN_TLS_FINAL, "PLUGIN_TLS_FINAL"); - map.insert(OPENVPN_PLUGIN_ENABLE_PF, "PLUGIN_ENABLE_PF"); - map.insert(OPENVPN_PLUGIN_ROUTE_PREDOWN, "PLUGIN_ROUTE_PREDOWN"); - map.insert(OPENVPN_PLUGIN_N, "PLUGIN_N"); - map - }; +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +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, } -/// Returns the name of an OPENVPN_PLUGIN_* constant. -pub fn plugin_event_name(num: c_int) -> &'static str { - PLUGIN_EVENT_NAMES.get(&num).map(|s| *s).unwrap_or("UNKNOWN") +impl 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 { + Err(ErrorKind::InvalidEnumVariant.into()) + } + } } @@ -60,20 +52,41 @@ mod tests { use super::*; #[test] - fn plugin_event_name_up() { - let name = plugin_event_name(0); - assert_eq!("PLUGIN_UP", name); + 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, _))); } #[test] - fn plugin_event_name_n() { - let name = plugin_event_name(13); - assert_eq!("PLUGIN_N", name); + fn from_int_invalid() { + let result = OpenVpnPluginEvent::from_int(14); + assert_matches!(result, Err(Error(ErrorKind::InvalidEnumVariant, _))); } #[test] - fn plugin_event_name_not_existing() { - let name = plugin_event_name(-15); - assert_eq!("UNKNOWN", name); + fn event_enum_to_str() { + let result = format!("{:?}", OpenVpnPluginEvent::Up); + assert_eq!("Up", result); } } diff --git a/talpid_openvpn_plugin/src/ffi/mod.rs b/talpid_openvpn_plugin/src/ffi/mod.rs index cf3b7fb42c..726bcae403 100644 --- a/talpid_openvpn_plugin/src/ffi/mod.rs +++ b/talpid_openvpn_plugin/src/ffi/mod.rs @@ -1,16 +1,32 @@ -/// FFI definitions for OpenVPN. See include/openvpn-plugin.h in the OpenVPN repository for -/// the original declarations of these structs and functions along with documentation for them: -/// https://github.com/OpenVPN/openvpn/blob/master/include/openvpn-plugin.h.in +// FFI definitions for OpenVPN. See include/openvpn-plugin.h in the OpenVPN repository for +// the original declarations of these structs and functions along with documentation for them: +// https://github.com/OpenVPN/openvpn/blob/master/include/openvpn-plugin.h.in use std::os::raw::{c_char, c_int, c_uint, c_void}; #[allow(dead_code)] -mod consts; +pub mod consts; use self::consts::*; mod parse; +error_chain!{ + errors { + InvalidEventType { + description("Invalid event type constant") + } + ParseEnvFailed { + description("Unable to parse environment variables from OpenVPN") + } + } +} + +/// All the OpenVPN events this plugin will register for listening to. Edit this variable to change +/// events. +pub static INTERESTING_EVENTS: &'static [OpenVpnPluginEvent] = &[OpenVpnPluginEvent::Up, + OpenVpnPluginEvent::RoutePredown]; + /// Struct sent to `openvpn_plugin_open_v3` containing input values. #[repr(C)] @@ -68,9 +84,12 @@ pub struct openvpn_plugin_args_func_return { #[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) + retptr: *mut openvpn_plugin_args_open_return) -> c_int { println!("openvpn_plugin_open_v3()"); + unsafe { + (*retptr).type_mask = events_to_bitmask(INTERESTING_EVENTS); + } OPENVPN_PLUGIN_FUNC_SUCCESS } @@ -88,7 +107,58 @@ 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 { - let event_name = unsafe { consts::plugin_event_name((*args).event_type) }; - println!("openvpn_plugin_func_v3({})", event_name); - OPENVPN_PLUGIN_FUNC_SUCCESS + // TODO(linus): Add logging of errors + match openvpn_plugin_func_v3_internal(args) { + Ok(_) => OPENVPN_PLUGIN_FUNC_SUCCESS, + Err(_) => 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)?; + println!("openvpn_plugin_func_v3({:?})", event); + + Ok(()) +} + + +/// Translates a collection of `OpenVpnPluginEvent` instances into a bitmask in the format OpenVPN +/// expects it. +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 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); + } } |
