falco_plugin/parse/
mod.rs

1//! # Event parsing support
2//!
3//! Plugins with event parsing capability can hook into an event stream and receive all of its events
4//! sequentially. The parsing phase is the stage in the event processing loop in which
5//! the Falcosecurity libraries inspect the content of the events' payload and use it to apply
6//! internal state updates or implement additional logic. This phase happens before any field
7//! extraction for a given event. Each event in a given stream is guaranteed to be received at most once.
8//!
9//! For your plugin to support event parsing, you will need to implement the [`ParsePlugin`]
10//! trait and invoke the [`parse_plugin`](crate::parse_plugin) macro, for example:
11//!
12//! ```
13//!# use std::ffi::CStr;
14//! use falco_event::events::RawEvent;
15//! use falco_plugin::anyhow::Error;
16//! use falco_plugin::base::Plugin;
17//! use falco_plugin::{parse_plugin, plugin};
18//! use falco_plugin::parse::{EventInput, ParseInput, ParsePlugin};
19//!# use falco_plugin::tables::TablesInput;
20//!
21//! struct MyParsePlugin;
22//!
23//! impl Plugin for MyParsePlugin {
24//!     // ...
25//! #    const NAME: &'static CStr = c"sample-plugin-rs";
26//! #    const PLUGIN_VERSION: &'static CStr = c"0.0.1";
27//! #    const DESCRIPTION: &'static CStr = c"A sample Falco plugin that does nothing";
28//! #    const CONTACT: &'static CStr = c"you@example.com";
29//! #    type ConfigType = ();
30//! #
31//! #    fn new(input: Option<&TablesInput>, config: Self::ConfigType)
32//! #        -> Result<Self, Error> {
33//! #        Ok(MyParsePlugin)
34//! #    }
35//! }
36//!
37//! impl ParsePlugin for MyParsePlugin {
38//!     type Event<'a> = RawEvent<'a>;
39//!
40//!     fn parse_event(&mut self, event: &EventInput<RawEvent>, parse_input: &ParseInput)
41//!         -> Result<(), Error> {
42//!         let event = event.event()?;
43//!
44//!         // any processing you want here, e.g. involving tables
45//!
46//!         Ok(())
47//!     }
48//! }
49//!
50//! plugin!(MyParsePlugin);
51//! parse_plugin!(MyParsePlugin);
52//! ```
53
54use crate::base::Plugin;
55use crate::error::last_error::LastError;
56use crate::parse::wrappers::ParsePluginExported;
57use crate::tables::LazyTableReader;
58use crate::tables::LazyTableWriter;
59use falco_event::events::{AnyEventPayload, RawEvent};
60use falco_plugin_api::ss_plugin_event_parse_input;
61
62#[doc(hidden)]
63pub mod wrappers;
64
65pub use crate::event::EventInput;
66
67/// Support for event parse plugins
68pub trait ParsePlugin: Plugin + ParsePluginExported {
69    /// # Parsed event type
70    ///
71    /// Events will be parsed into this type before being passed to the plugin, so you can
72    /// work directly on the deserialized form and don't need to worry about validating
73    /// the events.
74    ///
75    /// If an event fails this conversion, an error will be returned from [`EventInput::event`],
76    /// which you can propagate directly to the caller.
77    ///
78    /// If you don't want any specific validation/conversion to be performed, specify the type as
79    /// ```
80    /// type Event<'a> = falco_event::events::RawEvent<'a>;
81    /// ```
82    type Event<'a>: AnyEventPayload + TryFrom<&'a RawEvent<'a>>
83    where
84        Self: 'a;
85
86    /// # Parse an event
87    ///
88    /// Receives an event from the current capture and parses its content.
89    /// The plugin is guaranteed to receive an event at most once, after any
90    /// operation related to the event sourcing capability, and before
91    /// any operation related to the field extraction capability.
92    fn parse_event(
93        &mut self,
94        event: &EventInput<Self::Event<'_>>,
95        parse_input: &ParseInput,
96    ) -> anyhow::Result<()>;
97}
98
99/// # The input to a parse plugin
100///
101/// It has two fields containing the vtables needed to access tables imported through
102/// the [tables API](`crate::tables`).
103///
104/// You will pass these vtables to all methods that read or write data from tables,
105/// but you won't interact with them otherwise. They're effectively tokens proving
106/// you're in the right context to read/write tables.
107#[derive(Debug)]
108pub struct ParseInput<'t> {
109    /// Accessors to read table entries
110    pub reader: LazyTableReader<'t>,
111    /// Accessors to modify table entries
112    pub writer: LazyTableWriter<'t>,
113}
114
115impl ParseInput<'_> {
116    pub(crate) unsafe fn try_from(
117        value: *const ss_plugin_event_parse_input,
118        last_error: LastError,
119    ) -> Result<Self, anyhow::Error> {
120        let input = unsafe {
121            value
122                .as_ref()
123                .ok_or_else(|| anyhow::anyhow!("Got null event parse input"))?
124        };
125
126        let reader = unsafe {
127            input
128                .table_reader_ext
129                .as_ref()
130                .ok_or_else(|| anyhow::anyhow!("Got null reader vtable"))?
131        };
132        let writer = unsafe {
133            input
134                .table_writer_ext
135                .as_ref()
136                .ok_or_else(|| anyhow::anyhow!("Got null writer vtable"))?
137        };
138
139        let reader = LazyTableReader::new(reader, last_error.clone());
140        let writer = LazyTableWriter::try_from(writer, last_error)?;
141
142        Ok(Self { reader, writer })
143    }
144}