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}