summaryrefslogtreecommitdiffhomepage
path: root/talpid_openvpn_plugin
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-02-28 15:44:11 +0100
committerLinus Färnstrand <linus@mullvad.net>2017-02-28 15:44:11 +0100
commit0fdc6ef08987eb237aba81aee589b35fd8efbb2b (patch)
treec0da9e552109353a67193c949bbd8c2b8f8d2d68 /talpid_openvpn_plugin
parent4ce365c683dd5ee2ae084db6f1e7bd30fc0398ef (diff)
parent40f47e0ecf10c60687edbdcc5e2ad3999547ea74 (diff)
downloadmullvadvpn-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.rs109
-rw-r--r--talpid_openvpn_plugin/src/ffi/mod.rs86
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);
+ }
}