1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
use openvpn_plugin::{EventResult, EventType, openvpn_plugin};
use std::{collections::HashMap, ffi::CString, io, sync::Mutex};
use talpid_types::ErrorExt;
mod processing;
use crate::processing::EventProcessor;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("No core server id given as first argument")]
MissingCoreServerId,
// TODO: Remove box when upgrading tonic to a version with
// https://github.com/hyperium/tonic/pull/2282
#[error("Failed to send an event to daemon over the IPC channel")]
SendEvent(#[source] Box<tonic::Status>),
#[error("Unable to start Tokio runtime")]
CreateRuntime(#[source] io::Error),
#[error("Unable to create IPC transport")]
CreateTransport(#[source] tonic::transport::Error),
#[error("Unable to parse environment variables from OpenVPN")]
ParseEnvFailed(#[source] std::str::Utf8Error),
#[error("Unable to parse arguments from OpenVPN")]
ParseArgsFailed(#[source] std::str::Utf8Error),
#[error("Unhandled event type: {0:?}")]
UnhandledEvent(openvpn_plugin::EventType),
}
/// All the OpenVPN events this plugin will register for listening to. Edit this variable to change
/// events.
pub static INTERESTING_EVENTS: &[EventType] = &[
EventType::AuthFailed,
EventType::Up,
EventType::RouteUp,
EventType::RoutePredown,
];
openvpn_plugin!(
crate::openvpn_open,
crate::openvpn_close,
crate::openvpn_event,
crate::Mutex<Option<EventProcessor>>
);
pub struct Arguments {
ipc_socket_path: String,
}
fn openvpn_open(
args: Vec<CString>,
_env: HashMap<CString, CString>,
) -> Result<(Vec<EventType>, Mutex<Option<EventProcessor>>), Error> {
env_logger::init();
log::debug!("Initializing plugin");
let arguments = parse_args(&args)?;
log::info!(
"Connecting back to talpid core at {}",
arguments.ipc_socket_path
);
let processor = EventProcessor::new(arguments)?;
Ok((INTERESTING_EVENTS.to_vec(), Mutex::new(Some(processor))))
}
fn parse_args(args: &[CString]) -> Result<Arguments, Error> {
let mut args_iter = openvpn_plugin::ffi::parse::string_array_utf8(args)
.map_err(Error::ParseArgsFailed)?
.into_iter();
let _plugin_path = args_iter.next();
let ipc_socket_path: String = args_iter.next().ok_or(Error::MissingCoreServerId)?;
Ok(Arguments { ipc_socket_path })
}
fn openvpn_close(_handle: Mutex<Option<EventProcessor>>) {
log::info!("Unloading plugin");
}
fn openvpn_event(
event: EventType,
_args: Vec<CString>,
env: HashMap<CString, CString>,
handle: &mut Mutex<Option<EventProcessor>>,
) -> Result<EventResult, Error> {
log::debug!("Received event: {:?}", event);
let parsed_env = openvpn_plugin::ffi::parse::env_utf8(&env).map_err(Error::ParseEnvFailed)?;
let ctx = handle
.get_mut()
.expect("failed to obtain mutex for EventProcessor");
if let Some(processor) = ctx.as_mut() {
match processor.process_event(event, parsed_env) {
Ok(()) => Ok(EventResult::Success),
Err(e) => {
log::error!("{}", e.display_chain());
*ctx = None;
Ok(EventResult::Failure)
}
}
} else {
log::error!("Client has been closed");
Ok(EventResult::Failure)
}
}
|