falco_plugin/extract/
wrappers.rs1use crate::base::wrappers::PluginWrapper;
2use crate::error::ffi_result::FfiResult;
3use crate::error::panic::catch_panic;
4use crate::event::EventInput;
5use crate::extract::ExtractPlugin;
6use crate::tables::LazyTableReader;
7use falco_event::events::AnyEventPayload;
8use falco_plugin_api::plugin_api__bindgen_ty_2 as extract_plugin_api;
9use falco_plugin_api::ss_plugin_rc;
10use falco_plugin_api::{ss_plugin_event_input, ss_plugin_rc_SS_PLUGIN_FAILURE};
11use falco_plugin_api::{ss_plugin_field_extract_input, ss_plugin_t};
12use std::any::TypeId;
13use std::collections::BTreeMap;
14use std::ffi::{c_char, CString};
15use std::marker::PhantomData;
16use std::panic::AssertUnwindSafe;
17use std::sync::Mutex;
18
19#[diagnostic::on_unimplemented(
27 message = "Extract plugin is not exported",
28 note = "use either `extract_plugin!` or `static_plugin!`"
29)]
30pub unsafe trait ExtractPluginExported {}
31
32pub trait ExtractPluginFallbackApi {
33 const EXTRACT_API: extract_plugin_api = extract_plugin_api {
34 get_extract_event_types: None,
35 get_extract_event_sources: None,
36 get_fields: None,
37 extract_fields: None,
38 };
39
40 const IMPLEMENTS_EXTRACT: bool = false;
41}
42impl<T> ExtractPluginFallbackApi for T {}
43
44#[allow(missing_debug_implementations)]
45pub struct ExtractPluginApi<T>(std::marker::PhantomData<T>);
46
47impl<T: ExtractPlugin> ExtractPluginApi<T> {
48 pub const EXTRACT_API: extract_plugin_api = extract_plugin_api {
49 get_extract_event_types: Some(plugin_get_extract_event_types::<T>),
50 get_extract_event_sources: Some(plugin_get_extract_event_sources::<T>),
51 get_fields: Some(plugin_get_fields::<T>),
52 extract_fields: Some(plugin_extract_fields::<T>),
53 };
54
55 pub const IMPLEMENTS_EXTRACT: bool = true;
56}
57
58pub extern "C" fn plugin_get_fields<T: ExtractPlugin>() -> *const c_char {
59 T::get_fields().as_ptr()
60}
61
62pub unsafe extern "C" fn plugin_get_extract_event_types<T: ExtractPlugin>(
66 numtypes: *mut u32,
67 _plugin: *mut ss_plugin_t,
68) -> *mut u16 {
69 let types = T::Event::EVENT_TYPES;
70 unsafe { *numtypes = types.len() as u32 };
71 types.as_ptr().cast_mut() }
73
74pub extern "C" fn plugin_get_extract_event_sources<T: ExtractPlugin>() -> *const c_char {
76 static SOURCES: Mutex<BTreeMap<TypeId, CString>> = Mutex::new(BTreeMap::new());
77 let ty = TypeId::of::<T>();
78 let mut sources_map = SOURCES.lock().unwrap();
79 sources_map
82 .entry(ty)
83 .or_insert_with(|| {
84 let sources = serde_json::to_string(T::Event::event_sources().as_slice())
85 .expect("failed to serialize event source array");
86 CString::new(sources.into_bytes()).expect("failed to add NUL to event source array")
87 })
88 .as_ptr()
89}
90
91pub unsafe extern "C" fn plugin_extract_fields<T: ExtractPlugin>(
95 plugin: *mut ss_plugin_t,
96 event_input: *const ss_plugin_event_input,
97 extract_input: *const ss_plugin_field_extract_input,
98) -> ss_plugin_rc {
99 let plugin = plugin as *mut PluginWrapper<T>;
100 unsafe {
101 let Some(plugin) = plugin.as_mut() else {
102 return ss_plugin_rc_SS_PLUGIN_FAILURE;
103 };
104 let Some(actual_plugin) = &mut plugin.plugin else {
105 return ss_plugin_rc_SS_PLUGIN_FAILURE;
106 };
107
108 let Some(event_input) = event_input.as_ref() else {
109 return ss_plugin_rc_SS_PLUGIN_FAILURE;
110 };
111 let event_input = EventInput(*event_input, PhantomData);
112
113 let Some(extract_input) = extract_input.as_ref() else {
114 return ss_plugin_rc_SS_PLUGIN_FAILURE;
115 };
116
117 let fields =
118 std::slice::from_raw_parts_mut(extract_input.fields, extract_input.num_fields as usize);
119
120 let Some(reader_ext) = extract_input.table_reader_ext.as_ref() else {
121 return ss_plugin_rc_SS_PLUGIN_FAILURE;
122 };
123
124 let offsets = extract_input.value_offsets.as_mut();
125
126 let table_reader = LazyTableReader::new(reader_ext, actual_plugin.last_error.clone());
127
128 plugin.field_storage.reset();
129 catch_panic(AssertUnwindSafe(|| {
130 actual_plugin.plugin.extract_fields(
131 &event_input,
132 &table_reader,
133 fields,
134 offsets,
135 &plugin.field_storage,
136 )
137 }))
138 .rc(&mut plugin.error_buf)
139 }
140}
141
142#[macro_export]
147macro_rules! extract_plugin {
148 ($ty:ty) => {
149 unsafe impl $crate::extract::wrappers::ExtractPluginExported for $ty {}
150
151 $crate::wrap_ffi! {
152 #[unsafe(no_mangle)]
153 use $crate::extract::wrappers: <$ty>;
154
155 unsafe fn plugin_get_extract_event_sources() -> *const ::std::ffi::c_char;
156 unsafe fn plugin_get_extract_event_types(
157 numtypes: *mut u32,
158 plugin: *mut falco_plugin::api::ss_plugin_t,
159 ) -> *mut u16;
160 unsafe fn plugin_get_fields() -> *const ::std::ffi::c_char;
161 unsafe fn plugin_extract_fields(
162 plugin: *mut falco_plugin::api::ss_plugin_t,
163 event_input: *const falco_plugin::api::ss_plugin_event_input,
164 extract_input: *const falco_plugin::api::ss_plugin_field_extract_input,
165 ) -> i32;
166 }
167
168 #[allow(dead_code)]
169 fn __typecheck_plugin_extract_api() -> falco_plugin::api::plugin_api__bindgen_ty_2 {
170 falco_plugin::api::plugin_api__bindgen_ty_2 {
171 get_extract_event_sources: Some(plugin_get_extract_event_sources),
172 get_extract_event_types: Some(plugin_get_extract_event_types),
173 get_fields: Some(plugin_get_fields),
174 extract_fields: Some(plugin_extract_fields),
175 }
176 }
177 };
178}