pako_core/
plugin.rs

1use std::any::Any;
2
3use pako_tools::{Config, FiveTuple, Flow, Packet, ThreeTuple};
4
5use crate::{analyzer::L3Info, packet_info::PacketInfo, plugin_registry::PluginRegistry};
6
7/// Result struct manipulated by all plugins
8///
9/// Layer n means the *payload* of layer n
10pub enum PluginResult<'a> {
11    None,
12    Error(pako_tools::Error),
13    /// Layer 2: ethertype and payload
14    L2(u16, &'a [u8]),
15    /// Layer 3: L3 info (includes l2_proto, src, dst, and next layer proto), and payload
16    L3(&'a L3Info, &'a [u8]),
17    /// Layer 4: 5-tuple and payload
18    L4(FiveTuple, &'a [u8]),
19}
20
21#[derive(Debug, thiserror::Error)]
22pub enum PluginBuilderError {
23    /// Registration failed error
24    #[error("Plugin registration error {0:?}")]
25    Registration(String),
26}
27
28/// Plugin builder
29///
30/// A plugin build is responsible for creating plugin instances
31/// from the input configuration.
32pub trait PluginBuilder: Sync + Send {
33    /// Name of the plugin builder
34    fn name(&self) -> &'static str;
35    /// Builder function: instantiates zero or more plugins from configuration.
36    /// All created plugins must be registered to `registry`
37    fn build(
38        &self,
39        registry: &mut PluginRegistry,
40        config: &Config,
41    ) -> Result<(), PluginBuilderError>;
42}
43
44/// Indicates the plugin does not register any callback function
45pub const PLUGIN_NONE: u16 = 0;
46
47/// Indicates the plugin register for Layer 1 data
48pub const PLUGIN_L1: u16 = 0b0001;
49/// Indicates the plugin register for Layer 2 data
50pub const PLUGIN_L2: u16 = 0b0010;
51/// Indicates the plugin register for Layer 3 data
52pub const PLUGIN_L3: u16 = 0b0100;
53/// Indicates the plugin register for Layer 4 data
54pub const PLUGIN_L4: u16 = 0b1000;
55
56/// Indicates the plugin registers for 'flow created' events
57pub const PLUGIN_FLOW_NEW: u16 = 0b0001_0000;
58/// Indicates the plugin registers for 'flow destroyed' events
59pub const PLUGIN_FLOW_DEL: u16 = 0b0010_0000;
60
61/// Indicates the plugin register for all layers
62pub const PLUGIN_ALL: u16 = 0b1111_1111;
63
64/// Pcap/Pcap-ng analysis plugin instance
65///
66/// Plugins must be thread-safe because functions can (and will) be called
67/// concurrently from multiple threads.
68pub trait Plugin: Sync + Send {
69    // *Note*: lifetimes means that the reference on `input` must life as long
70    // as the plugin object (`'s` for `self`), while the result has a different lifetime,
71    // tied only to the input (`'i`)
72
73    /// Returns the name of the plugin instance
74    fn name(&self) -> &'static str;
75
76    /// Returns the layers registered by this plugin
77    fn plugin_type(&self) -> u16 {
78        PLUGIN_ALL
79    }
80
81    /// Plugin initialization function
82    /// Called before processing a pcap file
83    fn pre_process(&mut self) {}
84    /// Plugin end of processing function
85    /// Called after processing a pcap file
86    fn post_process(&mut self) {}
87
88    fn handle_layer_physical<'s, 'i>(
89        &'s mut self,
90        _packet: &'s Packet,
91        _data: &'i [u8],
92    ) -> PluginResult<'i> {
93        PluginResult::None
94    }
95
96    /// Callback function when layer 2 data is available
97    /// `data` is the raw ethernet data
98    /// `PLUGIN_L1` must be added to `plugin_type()` return
99    /// See crate::layers for possible linklayertype values
100    fn handle_layer_link<'s, 'i>(
101        &'s mut self,
102        _packet: &'s Packet,
103        _linklayertype: u16,
104        _data: &'i [u8],
105    ) -> PluginResult<'i> {
106        PluginResult::None
107    }
108
109    /// Callback function when layer 3 data is available
110    /// `packet` is the initial layer 3 packet information
111    /// `payload` is the layer 3 payload. It can be different from packet.data if defragmentation occured
112    /// `t3` is the three-tuple of the connection
113    /// `PLUGIN_L3` must be added to `plugin_type()` return
114    fn handle_layer_network<'s, 'i>(
115        &'s mut self,
116        _packet: &'s Packet,
117        _payload: &'i [u8],
118        _t3: &'s ThreeTuple,
119    ) -> PluginResult<'i> {
120        PluginResult::None
121    }
122
123    /// Callback function when layer 4 data is available
124    /// `packet` is the initial layer 3 packet information
125    /// `pinfo` is the flow and layers information, including payload
126    /// `PLUGIN_L4` must be added to `plugin_type()` return
127    fn handle_layer_transport<'s, 'i>(
128        &'s mut self,
129        _packet: &'s Packet,
130        _pinfo: &PacketInfo,
131    ) -> PluginResult<'i> {
132        PluginResult::None
133    }
134    /// Callback function when a new flow is created
135    /// `PLUGIN_FLOW_NEW` must be added to `plugin_type()` return
136    fn flow_created(&mut self, _flow: &Flow) {}
137    /// Callback function when a flow is destroyed
138    /// `PLUGIN_FLOW_DEL` must be added to `plugin_type()` return
139    fn flow_destroyed(&mut self, _flow: &Flow) {}
140
141    /// Get results, if present
142    fn get_results(&mut self) -> Option<Box<dyn Any>> {
143        None
144    }
145
146    /// Save results to specified directory
147    fn save_results(&mut self, _path: &str) -> Result<(), &'static str> {
148        Ok(())
149    }
150}
151
152/// Derives a plugin builder
153///
154/// A closure can be passed as third argument. This closure receives a `Config`
155/// object and must return an instance of plugin.
156///
157/// By default (if no closure was provided), the plugin is created
158/// using the `Plugin::default()` function.
159///
160/// Note: the plugin builder may create plugins of different types
161#[macro_export]
162macro_rules! plugin_builder {
163    ($name:ident, $builder_name:ident, $build_fn:expr) => {
164        pub struct $builder_name;
165
166        impl $crate::PluginBuilder for $builder_name {
167            fn name(&self) -> &'static str {
168                stringify!($builder_name)
169            }
170            fn build(
171                &self,
172                registry: &mut $crate::PluginRegistry,
173                config: &pako_tools::Config,
174            ) -> Result<(), $crate::PluginBuilderError> {
175                let plugin = $build_fn(config);
176                let protos = plugin.plugin_type();
177                let safe_p = $crate::build_safeplugin!(plugin);
178                let id = registry.add_plugin(safe_p);
179                if protos & $crate::PLUGIN_L2 != 0 {
180                    // XXX no filter, so register for all
181                    registry.register_layer(2, 0, id)?;
182                }
183                if protos & $crate::PLUGIN_L3 != 0 {
184                    // XXX no filter, so register for all
185                    registry.register_layer(3, 0, id)?;
186                }
187                if protos & $crate::PLUGIN_L4 != 0 {
188                    // XXX no filter, so register for all
189                    registry.register_layer(4, 0, id)?;
190                }
191                Ok(())
192            }
193        }
194    };
195    ($name:ident, $builder_name:ident) => {
196        $crate::plugin_builder!($name, $builder_name, |_| $name::default());
197    };
198}
199/// Derives a plugin builder relying on the Plugin::default() function
200#[macro_export]
201macro_rules! default_plugin_builder {
202    ($name:ident, $builder:ident) => {
203        $crate::plugin_builder!($name, $builder, |_| $name::default());
204    };
205}