macro_rules! openvpn_plugin {
    ($open_fn:path, $close_fn:path, $event_fn:path, $handle_ty:ty) => { ... };
}
Expand description

The main part of this crate. The macro generates the public FFI functions that OpenVPN looks for in a shared library:

  • openvpn_plugin_open_v3 - Will call $open_fn
  • openvpn_plugin_close_v1 - Will call $close_fn
  • openvpn_plugin_func_v3 - Will call $event_fn

This macro must be called in the crate root of the crate you wish to become an OpenVPN plugin. That is because the FFI functions must be publicly exported from the shared library for OpenVPN to find them.

See the top level library documentation and the included debug-plugin crate for examples on how to use this macro.

$open_fn - The plugin load callback

Should be a function with the following signature:

fn foo_open(
    args: Vec<CString>,
    env: HashMap<CString, CString>
) -> Result<(Vec<EventType>, Handle), Error> {
    /// ...
}

With foo_open substituted for a function name of your liking and Handle being the $handle_ty handle type you pass.

The type of the error in the result from this function does not matter, as long as it implements std::error::Error. Any error returned is logged and then OPENVPN_PLUGIN_FUNC_ERROR is returned to OpenVPN, which indicates that the plugin failed to load and OpenVPN will abort and exit.

This function will be called by OpenVPN when the plugin is loaded, just as OpenVPN starts.

This function has access to the arguments passed to the plugin and the initial OpenVPN environment. If the plugin deems the open operation successful it should return a vector with the events it wants to register for and the handle instance that the plugin can use to keep state (See further down for more on the handle).

The openvpn_plugin::ffi::parse::{string_array_utf8, env_utf8} functions can be used to try to convert the arguments and environment into Rust Strings.

$close_fn - The plugin unload callback

Should be a function with the following signature:

fn foo_close(handle: Handle) {
    /// ...
}

With foo_close substituted for a function name of your liking and Handle being the $handle_ty handle type you pass.

This function is called just before the plugin is unloaded, just before OpenVPN shuts down. Here the plugin can do any cleaning up that is necessary. Since the handle is passed by value it will be dropped when this function returns.

$event_fn - The event callback function

Should be a function with the following signature:

fn foo_event(
    event: EventType,
    args: Vec<CString>,
    env: HashMap<CString, CString>,
    handle: &mut Handle,
) -> Result<EventResult, Error> {
    /// ...
}

With foo_event substituted for a function name of your liking and Handle being the $handle_ty handle type you pass.

The type of the error in the result from this function does not matter, as long as it implements std::error::Error. Any error returned is logged and then OPENVPN_PLUGIN_FUNC_ERROR is returned to OpenVPN. OPENVPN_PLUGIN_FUNC_ERROR indicates different things on different events. In the case of an authentication request or TLS key verification it means that the request is denied and the connection is aborted.

This function is being called by OpenVPN each time one of the events that $open_fn registered for happens. This can for example be that a tunnel is established or that a client wants to authenticate.

The first argument, EventType, will tell which event that is happening.

$handle_ty - The handle type

The handle must be created and returned by the $open_fn function and will be kept for the entire runtime of the plugin. The handle is passed to every subsequent callback and this is the way that the plugin is supposed to keep state between each callback.

The handle instance is being dropped upon return from the $close_fn function just as the plugin is being unloaded.