falco_plugin/plugin/source/
mod.rs

1use crate::plugin::base::Plugin;
2use crate::plugin::source::wrappers::SourcePluginExported;
3use crate::source::{EventBatch, EventInput};
4use falco_event::events::types::PPME_PLUGINEVENT_E as PluginEvent;
5use falco_event::events::Event;
6use falco_event::events::EventMetadata;
7use std::ffi::{CStr, CString};
8
9pub mod event_batch;
10pub mod open_params;
11#[doc(hidden)]
12pub mod wrappers;
13
14/// # Support for event sourcing plugins
15pub trait SourcePlugin: Plugin + SourcePluginExported {
16    /// # Instance type
17    ///
18    /// Each source plugin defines an instance type. The instance is the object responsible
19    /// for actual generation of events. The plugin type mostly serves as a way to create
20    /// and destroy instances.
21    ///
22    /// **Note**: while there may be multiple instances for a particular plugin, there will be
23    /// at most one at any given time.
24    type Instance: SourcePluginInstance<Plugin = Self>;
25
26    /// # Event source name
27    ///
28    /// This string describes the event source. One notable event source name is `syscall`,
29    /// for plugins collecting syscall information.
30    ///
31    /// If the plugin defines both `EVENT_SOURCE` (as a non-empty string) and `PLUGIN_ID`
32    /// (as a non-zero value), it will only be allowed to emit events of type [`PluginEvent`]
33    /// with the `plugin_id` field matching `PLUGIN_ID` in the definition of this trait.
34    ///
35    /// This constant must be a non-empty string if `PLUGIN_ID` is set.
36    const EVENT_SOURCE: &'static CStr;
37
38    /// # Plugin ID
39    ///
40    /// This is the unique ID of the plugin.
41    ///
42    /// If the plugin defines both `EVENT_SOURCE` (as a non-empty string) and `PLUGIN_ID`
43    /// (as a non-zero value), it will only be allowed to emit events of type [`PluginEvent`]
44    /// with the `plugin_id` field matching `PLUGIN_ID` in the definition of this trait.
45    ///
46    /// > EVERY PLUGIN WITH EVENT SOURCING CAPABILITY IMPLEMENTING A SPECIFIC EVENT SOURCE MUST
47    /// > OBTAIN AN OFFICIAL ID FROM THE FALCOSECURITY ORGANIZATION, OTHERWISE IT WON'T PROPERLY
48    /// > COEXIST WITH OTHER PLUGINS.
49    const PLUGIN_ID: u32;
50
51    /// # List sample open parameters
52    ///
53    /// Return a list of suggested open parameters supported by this plugin.
54    /// Any of the values in the returned list are valid parameters for open().
55    ///
56    /// The default implementation returns an empty string, but you can use
57    /// [`crate::source::serialize_open_params`] and [`crate::source::OpenParam`] to build
58    /// a description of what the [`SourcePlugin::open`] method expects.
59    ///
60    /// **Note**: as of API version 3.4.0, this appears unused.
61    fn list_open_params(&mut self) -> Result<&CStr, anyhow::Error> {
62        Ok(c"")
63    }
64
65    /// # Open a capture instance
66    ///
67    /// This method receives the `open` parameter from Falco configuration and returns
68    /// a new instance of the source plugin.
69    fn open(&mut self, params: Option<&str>) -> Result<Self::Instance, anyhow::Error>;
70
71    /// # Close a capture instance
72    ///
73    /// The default implementation does nothing, leaving all cleanup to the instance type's
74    /// [`Drop`] implementation, if any.
75    fn close(&mut self, _instance: &mut Self::Instance) {}
76
77    /// # Render an event to string
78    ///
79    /// This string will be available as `%evt.plugininfo` in Falco rules. You may consider
80    /// using the helpers from [`crate::strings`] to build the resulting CString.
81    fn event_to_string(&mut self, event: &EventInput) -> Result<CString, anyhow::Error>;
82}
83
84/// Information about capture progress
85#[derive(Debug)]
86pub struct ProgressInfo<'a> {
87    /// Progress percentage (0.0-100.0)
88    pub value: f64,
89    /// Optional detailed message about the progress
90    pub detail: Option<&'a CStr>,
91}
92
93pub(crate) struct SourcePluginInstanceWrapper<I: SourcePluginInstance> {
94    pub(crate) instance: I,
95    pub(crate) batch: bumpalo::Bump,
96}
97
98/// # An open instance of a source plugin
99pub trait SourcePluginInstance {
100    /// # The [`SourcePlugin`] this instance belongs to.
101    ///
102    /// Source plugin and instance types must correspond 1:1 to each other.
103    type Plugin: SourcePlugin<Instance = Self>;
104
105    /// # Fill the next batch of events
106    ///
107    /// This is the most important method for the source plugin implementation. It is responsible
108    /// for actually generating the events for the main event loop.
109    ///
110    /// For performance, events are returned in batches. Of course, it's entirely valid to have
111    /// just a single event in a batch.
112    ///
113    /// ## Returning one or more events
114    ///
115    /// For each event that is ready, pass it to `batch.add()` to add it to the current batch
116    /// to be returned.
117    ///
118    /// ```ignore
119    /// fn next_batch(
120    ///     &mut self,
121    ///     plugin: &mut Self::Plugin,
122    ///     batch: &mut EventBatch,
123    /// ) -> Result<(), anyhow::Error> {
124    ///     let mut event = Vec::new();
125    ///     // ...
126    ///     let event = Self::plugin_event(&event);
127    ///     batch.add(event)?;
128    ///     Ok(())
129    /// }
130    /// ```
131    ///
132    /// ## Returning no events, temporarily
133    ///
134    /// If there are no events to return at the moment but there might be later, you should
135    /// return [`FailureReason::Timeout`](`crate::FailureReason::Timeout`) as the error. The plugin framework will retry the call
136    /// to `next_batch` later.
137    ///
138    /// ```ignore
139    /// fn next_batch(
140    ///     &mut self,
141    ///     plugin: &mut Self::Plugin,
142    ///     batch: &mut EventBatch,
143    /// ) -> Result<(), anyhow::Error> {
144    ///     std::thread::sleep(Duration::from_millis(100));
145    ///     Err(anyhow::anyhow!("no events right now").context(FailureReason::Timeout))
146    /// }
147    /// ```
148    ///
149    /// ## Returning no events, permanently
150    ///
151    /// If there will be no more events coming from this instance, you should return\
152    /// [`FailureReason::Eof`](`crate::FailureReason::Eof`) as the error. The plugin framework will end the capture and shut down
153    /// gracefully.
154    ///
155    /// ```ignore
156    /// fn next_batch(
157    ///     &mut self,
158    ///     plugin: &mut Self::Plugin,
159    ///     batch: &mut EventBatch,
160    /// ) -> Result<(), anyhow::Error> {
161    ///     Err(anyhow::anyhow!("no more events").context(FailureReason::Eof))
162    /// }
163    /// ```
164    ///
165    /// ## Timing considerations
166    ///
167    /// This method is effectively called in a loop by Falco and there's a delicate balance of
168    /// how much time to spend here waiting for events. On the one hand, you don't want to poll
169    /// in a tight loop, since that leads to excessive CPU usage. On the other hand, you don't
170    /// want to sleep forever waiting for an event, since it may block other tasks running in the
171    /// main event loop thread. As a rule of thumb, waiting up to 10-100 milliseconds for an event
172    /// works fine.
173    fn next_batch(
174        &mut self,
175        plugin: &mut Self::Plugin,
176        batch: &mut EventBatch,
177    ) -> Result<(), anyhow::Error>;
178
179    /// # Get progress information
180    ///
181    /// If your plugin reads from a source that has a well-defined end (like a file),
182    /// you can use this method to report progress information.
183    ///
184    /// It consists of a percentage (0.0-100.0) and an optional description containing more
185    /// details about the progress (e.g. bytes read/bytes total).
186    fn get_progress(&mut self) -> ProgressInfo {
187        ProgressInfo {
188            value: 0.0,
189            detail: None,
190        }
191    }
192
193    /// # A helper for generating plugin events
194    ///
195    /// If your plugin defines a PLUGIN_ID and a source name, the only allowed events are
196    /// of type [`PluginEvent`] and effectively the only customizable field is the event data
197    /// (which is a generic byte buffer).
198    ///
199    /// This method makes it easy to generate such events: just pass it the event data and get
200    /// the complete event, with all the metadata set to reasonable defaults.
201    fn plugin_event(data: &[u8]) -> Event<PluginEvent> {
202        let event = PluginEvent {
203            plugin_id: Some(Self::Plugin::PLUGIN_ID),
204            event_data: Some(data),
205        };
206
207        let metadata = EventMetadata::default();
208
209        Event {
210            metadata,
211            params: event,
212        }
213    }
214}