falco_plugin/source/mod.rs
1//! # Event sourcing support
2//!
3//! Plugins with event sourcing capability provide a new event source and make it available to
4//! libscap and libsinsp. They have the ability to "open" and "close" a stream of events and return
5//! those events to the plugin framework. They also provide a plugin ID, which is globally unique
6//! and is used in capture files. Event sources provided by plugins with this capability are tied
7//! to the events they generate and can be used by [plugins with field extraction](crate::source)
8//! capabilities and within Falco rules.
9//! For your plugin to support event sourcing, you will need to implement the [`SourcePlugin`]
10//! trait and invoke the [`source_plugin`](crate::source_plugin) macro, for example:
11//!
12//! ```
13//! use std::ffi::{CStr, CString};
14//! use anyhow::Error;
15//! use falco_event::events::{Event, RawEvent};
16//! use falco_plugin::base::{Metric, Plugin};
17//! use falco_plugin::{plugin, source_plugin};
18//! use falco_plugin::source::{EventBatch, EventInput, PluginEvent, SourcePlugin, SourcePluginInstance};
19//! use falco_plugin::tables::TablesInput;
20//! use falco_plugin_api::ss_plugin_event_input;
21//!
22//! struct MySourcePlugin;
23//!
24//! impl Plugin for MySourcePlugin {
25//! // ...
26//! # const NAME: &'static CStr = c"sample-plugin-rs";
27//! # const PLUGIN_VERSION: &'static CStr = c"0.0.1";
28//! # const DESCRIPTION: &'static CStr = c"A sample Falco plugin that does nothing";
29//! # const CONTACT: &'static CStr = c"you@example.com";
30//! # type ConfigType = ();
31//! #
32//! # fn new(input: Option<&TablesInput>, config: Self::ConfigType)
33//! # -> Result<Self, anyhow::Error> {
34//! # Ok(MySourcePlugin)
35//! # }
36//! #
37//! # fn set_config(&mut self, config: Self::ConfigType) -> Result<(), anyhow::Error> {
38//! # Ok(())
39//! # }
40//! #
41//! # fn get_metrics(&mut self) -> impl IntoIterator<Item=Metric> {
42//! # []
43//! # }
44//! }
45//!
46//! struct MySourcePluginInstance;
47//!
48//! impl SourcePlugin for MySourcePlugin {
49//! type Instance = MySourcePluginInstance;
50//! const EVENT_SOURCE: &'static CStr = c"my-source-plugin";
51//! const PLUGIN_ID: u32 = 0; // we do not have one assigned for this example :)
52//!
53//! type Event<'a> = Event<PluginEvent<&'a [u8]>>;
54//!
55//! fn open(&mut self, params: Option<&str>) -> Result<Self::Instance, Error> {
56//! // we do not use the open parameters in this example
57//! Ok((MySourcePluginInstance))
58//! }
59//!
60//! fn event_to_string(&mut self, event: &EventInput<Self::Event<'_>>) -> Result<CString, Error> {
61//! // a string representation for our event; just copy out the whole event data
62//! // (it's an ASCII string); please note we need the copy because we need to add
63//! // a NUL terminator to convert the byte buffer to a C string
64//!
65//! // get the plugin event
66//! let plugin_event = event.event()?;
67//!
68//! // convert the data to a CString and return it
69//! Ok(CString::new(plugin_event.params.event_data)?)
70//! }
71//! }
72//!
73//! impl SourcePluginInstance for MySourcePluginInstance {
74//! type Plugin = MySourcePlugin;
75//!
76//! fn next_batch(&mut self, plugin: &mut Self::Plugin, batch: &mut EventBatch)
77//! -> Result<(), Error> {
78//! let event = Self::plugin_event(b"hello, world");
79//! batch.add(event)?;
80//!
81//! Ok(())
82//! }}
83//!
84//! plugin!(MySourcePlugin);
85//! source_plugin!(MySourcePlugin);
86//! ```
87
88use crate::base::Plugin;
89use crate::source::wrappers::SourcePluginExported;
90use falco_event::events::{AnyEventPayload, EventMetadata};
91use falco_event::events::{Event, RawEvent};
92use std::ffi::{CStr, CString};
93
94mod event_batch;
95mod open_params;
96#[doc(hidden)]
97pub mod wrappers;
98
99pub use crate::event::EventInput;
100pub use crate::event::PluginEvent;
101pub use event_batch::EventBatch;
102pub use open_params::{serialize_open_params, OpenParam};
103
104/// Support for event sourcing plugins
105pub trait SourcePlugin: Plugin + SourcePluginExported {
106 /// # Instance type
107 ///
108 /// Each source plugin defines an instance type. The instance is the object responsible
109 /// for actual generation of events. The plugin type mostly serves as a way to create
110 /// and destroy instances.
111 ///
112 /// **Note**: while there may be multiple instances for a particular plugin, there will be
113 /// at most one at any given time.
114 type Instance: SourcePluginInstance<Plugin = Self>;
115
116 /// # Event source name
117 ///
118 /// This string describes the event source. One notable event source name is `syscall`,
119 /// for plugins collecting syscall information.
120 ///
121 /// If the plugin defines both `EVENT_SOURCE` (as a non-empty string) and `PLUGIN_ID`
122 /// (as a non-zero value), it will only be allowed to emit plugin events (e.g. [`crate::event::PluginEvent`])
123 /// with the `plugin_id` field matching `PLUGIN_ID` in the definition of this trait.
124 ///
125 /// This constant must be a non-empty string if `PLUGIN_ID` is set.
126 const EVENT_SOURCE: &'static CStr;
127
128 /// # Plugin ID
129 ///
130 /// This is the unique ID of the plugin.
131 ///
132 /// If the plugin defines both `EVENT_SOURCE` (as a non-empty string) and `PLUGIN_ID`
133 /// (as a non-zero value), it will only be allowed to emit plugin events (e.g. [`crate::event::PluginEvent`])
134 /// with the `plugin_id` field matching `PLUGIN_ID` in the definition of this trait.
135 ///
136 /// > EVERY PLUGIN WITH EVENT SOURCING CAPABILITY IMPLEMENTING A SPECIFIC EVENT SOURCE MUST
137 /// > OBTAIN AN OFFICIAL ID FROM THE FALCOSECURITY ORGANIZATION, OTHERWISE IT WON'T PROPERLY
138 /// > COEXIST WITH OTHER PLUGINS.
139 const PLUGIN_ID: u32;
140
141 /// # Event type handled by this plugin
142 ///
143 /// The SDK does not enforce limits on the events generated, but you can make your life
144 /// a bit easier in `event_to_string` by specifying the event type your plugin generates here.
145 /// Events will be parsed into this type before being passed to the plugin, so you can
146 /// work directly on the deserialized form and don't need to worry about validating
147 /// the events.
148 ///
149 /// If an event fails this conversion, an error will be returned from the SDK and your
150 /// string formatting code won't be called.
151 ///
152 /// If you don't want any specific validation/conversion to be performed, specify the type as
153 /// ```
154 /// type Event<'a> = falco_event::events::RawEvent<'a>;
155 /// ```
156 type Event<'a>: AnyEventPayload + TryFrom<&'a RawEvent<'a>>
157 where
158 Self: 'a;
159
160 /// # List sample open parameters
161 ///
162 /// Return a list of suggested open parameters supported by this plugin.
163 /// Any of the values in the returned list are valid parameters for open().
164 ///
165 /// The default implementation returns an empty string, but you can use
166 /// [`crate::source::serialize_open_params`] and [`crate::source::OpenParam`] to build
167 /// a description of what the [`SourcePlugin::open`] method expects.
168 ///
169 /// **Note**: as of API version 3.4.0, this appears unused.
170 fn list_open_params(&mut self) -> Result<&CStr, anyhow::Error> {
171 Ok(c"")
172 }
173
174 /// # Open a capture instance
175 ///
176 /// This method receives the `open` parameter from Falco configuration and returns
177 /// a new instance of the source plugin.
178 fn open(&mut self, params: Option<&str>) -> Result<Self::Instance, anyhow::Error>;
179
180 /// # Close a capture instance
181 ///
182 /// The default implementation does nothing, leaving all cleanup to the instance type's
183 /// [`Drop`] implementation, if any.
184 fn close(&mut self, _instance: &mut Self::Instance) {}
185
186 /// # Render an event to string
187 ///
188 /// This string will be available as `%evt.plugininfo` in Falco rules. You may consider
189 /// using the helpers from [`crate::strings`] to build the resulting CString.
190 fn event_to_string(
191 &mut self,
192 event: &EventInput<Self::Event<'_>>,
193 ) -> Result<CString, anyhow::Error>;
194}
195
196/// Information about capture progress
197#[derive(Debug)]
198pub struct ProgressInfo<'a> {
199 /// Progress percentage (0.0-100.0)
200 pub value: f64,
201 /// Optional detailed message about the progress
202 pub detail: Option<&'a CStr>,
203}
204
205struct SourcePluginInstanceWrapper<I: SourcePluginInstance> {
206 instance: I,
207 batch: bumpalo::Bump,
208}
209
210/// # An open instance of a source plugin
211pub trait SourcePluginInstance {
212 /// # The [`SourcePlugin`] this instance belongs to.
213 ///
214 /// Source plugin and instance types must correspond 1:1 to each other.
215 type Plugin: SourcePlugin<Instance = Self>;
216
217 /// # Fill the next batch of events
218 ///
219 /// This is the most important method for the source plugin implementation. It is responsible
220 /// for actually generating the events for the main event loop.
221 ///
222 /// For performance, events are returned in batches. Of course, it's entirely valid to have
223 /// just a single event in a batch.
224 ///
225 /// ## Returning one or more events
226 ///
227 /// For each event that is ready, pass it to `batch.add()` to add it to the current batch
228 /// to be returned.
229 ///
230 /// ```ignore
231 /// fn next_batch(
232 /// &mut self,
233 /// plugin: &mut Self::Plugin,
234 /// batch: &mut EventBatch,
235 /// ) -> Result<(), anyhow::Error> {
236 /// let mut event = Vec::new();
237 /// // ...
238 /// let event = Self::plugin_event(&event);
239 /// batch.add(event)?;
240 /// Ok(())
241 /// }
242 /// ```
243 ///
244 /// ## Returning no events, temporarily
245 ///
246 /// If there are no events to return at the moment but there might be later, you should
247 /// return [`FailureReason::Timeout`](`crate::FailureReason::Timeout`) as the error. The plugin framework will retry the call
248 /// to `next_batch` later.
249 ///
250 /// ```ignore
251 /// fn next_batch(
252 /// &mut self,
253 /// plugin: &mut Self::Plugin,
254 /// batch: &mut EventBatch,
255 /// ) -> Result<(), anyhow::Error> {
256 /// std::thread::sleep(Duration::from_millis(100));
257 /// Err(anyhow::anyhow!("no events right now").context(FailureReason::Timeout))
258 /// }
259 /// ```
260 ///
261 /// ## Returning no events, permanently
262 ///
263 /// If there will be no more events coming from this instance, you should return\
264 /// [`FailureReason::Eof`](`crate::FailureReason::Eof`) as the error. The plugin framework will end the capture and shut down
265 /// gracefully.
266 ///
267 /// ```ignore
268 /// fn next_batch(
269 /// &mut self,
270 /// plugin: &mut Self::Plugin,
271 /// batch: &mut EventBatch,
272 /// ) -> Result<(), anyhow::Error> {
273 /// Err(anyhow::anyhow!("no more events").context(FailureReason::Eof))
274 /// }
275 /// ```
276 ///
277 /// ## Timing considerations
278 ///
279 /// This method is effectively called in a loop by Falco and there's a delicate balance of
280 /// how much time to spend here waiting for events. On the one hand, you don't want to poll
281 /// in a tight loop, since that leads to excessive CPU usage. On the other hand, you don't
282 /// want to sleep forever waiting for an event, since it may block other tasks running in the
283 /// main event loop thread. As a rule of thumb, waiting up to 10-100 milliseconds for an event
284 /// works fine.
285 fn next_batch(
286 &mut self,
287 plugin: &mut Self::Plugin,
288 batch: &mut EventBatch,
289 ) -> Result<(), anyhow::Error>;
290
291 /// # Get progress information
292 ///
293 /// If your plugin reads from a source that has a well-defined end (like a file),
294 /// you can use this method to report progress information.
295 ///
296 /// It consists of a percentage (0.0-100.0) and an optional description containing more
297 /// details about the progress (e.g. bytes read/bytes total).
298 fn get_progress(&mut self) -> ProgressInfo<'_> {
299 ProgressInfo {
300 value: 0.0,
301 detail: None,
302 }
303 }
304
305 /// # A helper for generating plugin events
306 ///
307 /// If your plugin defines a PLUGIN_ID and a source name, the only allowed events are
308 /// plugin events (e.g. [`crate::event::PluginEvent`]), and effectively the only customizable
309 /// field is the event data (which is a generic byte buffer).
310 ///
311 /// This method makes it easy to generate such events: just pass it the event data and get
312 /// the complete event, with all the metadata set to reasonable defaults.
313 fn plugin_event(data: &[u8]) -> Event<PluginEvent<&[u8]>> {
314 let event = PluginEvent {
315 plugin_id: Self::Plugin::PLUGIN_ID,
316 event_data: data,
317 };
318
319 let metadata = EventMetadata::default();
320
321 Event {
322 metadata,
323 params: event,
324 }
325 }
326}