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}