Crate openvpn_plugin
source ·Expand description
openvpn-plugin
is a crate that makes it easy to write OpenVPN plugins in Rust.
The crate contains two main things:
- The
openvpn_plugin!
macro for generating the FFI interface OpenVPN will interact with - The FFI and safe Rust types needed to communicate with OpenVPN.
Usage
Edit your Cargo.toml
to depend on this crate and set the type of your crate to a cdylib
in
order to make it compile to a shared library that OpenVPN will understand:
[lib]
crate-type = ["cdylib"]
[dependencies]
openvpn-plugin = "x.y"
In your crate root (lib.rs
) define your handle type, the three callback functions and
call the openvpn_plugin!
macro to generate the corresponding FFI bindings.
More details on the handle and the callback functions can be found in the documentation for the
openvpn_plugin!
macro.
use std::collections::HashMap;
use std::ffi::CString;
use std::io::Error;
use openvpn_plugin::{openvpn_plugin, EventResult, EventType};
pub struct Handle {
// Fields needed for the plugin to keep state between callbacks
}
fn openvpn_open(
args: Vec<CString>,
env: HashMap<CString, CString>,
) -> Result<(Vec<EventType>, Handle), Error> {
// Listen to only the `Up` event, which will be fired when a tunnel has been established.
let events = vec![EventType::Up];
// Create the handle instance.
let handle = Handle { /* ... */ };
Ok((events, handle))
}
fn openvpn_close(handle: Handle) {
println!("Plugin is closing down");
}
fn openvpn_event(
event: EventType,
args: Vec<CString>,
env: HashMap<CString, CString>,
handle: &mut Handle,
) -> Result<EventResult, Error> {
/* Process the event */
// If the processing worked fine and/or the request the callback represents should be
// accepted, return EventResult::Success. See EventResult docs for more info.
Ok(EventResult::Success)
}
openvpn_plugin!(crate::openvpn_open, crate::openvpn_close, crate::openvpn_event, Handle);
Panic handling
C cannot handle Rust panic unwinding into it, so it is not good practice to let Rust panic when
called from C. Because of this, all calls from this crate to the callbacks given to
openvpn_plugin!
($open_fn
, $close_fn
and $event_fn
) are wrapped in
catch_unwind
.
If catch_unwind
captures a panic it will log it and then return
OPENVPN_PLUGIN_FUNC_ERROR
to OpenVPN.
Note that this will only work for unwinding panics, not with panic=abort
.
Logging
Any errors returned from the user defined callbacks or panics that happens anywhere in Rust is
logged by this crate before control is returned to OpenVPN. By default logging happens to
stderr. To activate logging with the error!
macro in the log
crate, build this crate with
the log
feature.
Modules
- FFI types and functions used by the plugin to convert between the types OpenVPN pass and expect back and the Rust types the plugin will be exposed to.
Macros
- The main part of this crate. The macro generates the public FFI functions that OpenVPN looks for in a shared library:
Enums
- Enum representing the results an OpenVPN plugin can return from an event callback.
- All the events that an OpenVPN plugin can register for and get notified about. This is a Rust representation of the constants named
OPENVPN_PLUGIN_*
inopenvpn-plugin.h
.