From 1a5aa30e4759059f52cc95973d536d9dbef2b316 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 2 Jun 2021 15:48:36 -0600 Subject: [PATCH 1/4] rust/conf: export ConfNodeLookupChild to rust --- rust/src/conf.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rust/src/conf.rs b/rust/src/conf.rs index 50cc07257009..eae746360c9a 100644 --- a/rust/src/conf.rs +++ b/rust/src/conf.rs @@ -39,6 +39,7 @@ extern { fn ConfGetChildValueBool(conf: *const c_void, key: *const c_char, vptr: *mut c_int) -> i8; fn ConfGetNode(key: *const c_char) -> *const c_void; + fn ConfNodeLookupChild(node: *const c_void, name: *const c_char) -> *const c_void; } pub fn conf_get_node(key: &str) -> Option { @@ -142,6 +143,22 @@ impl ConfNode { return false; } + // Get a child node of this node by name. + // + // Wrapper around ConfNodeLookupChild. + // + // Returns None if the child is not found. + pub fn get_child(&self, name: &str) -> Option { + unsafe { + let name = CString::new(name).unwrap(); + let child = ConfNodeLookupChild(self.conf, name.as_ptr()); + if child.is_null() { + None + } else { + Some(ConfNode { conf: child }) + } + } + } } const BYTE: u64 = 1; From 8e8a1eba5ffe1ef5ded10b40427b6419919e1fa9 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 09:40:34 -0600 Subject: [PATCH 2/4] rust/debug: make pub, so plugins can use logging --- rust/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index f28e4c249ace..ad280a368d2d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -83,7 +83,7 @@ extern crate suricata_derive; pub mod core; #[macro_use] -pub(crate) mod debug; +pub mod debug; pub mod common; pub mod conf; From 8b126705ba0936f5989e0243d679e9ab5141a6b4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 13:32:49 -0600 Subject: [PATCH 3/4] rust/plugins: fix logging initialization With the recent refactor, the log level as seen by plugins was not being updated when being set through the C interface, so just set it directly upon plugin initialization. --- rust/src/plugin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/src/plugin.rs b/rust/src/plugin.rs index 7f3758640846..db47131848e5 100644 --- a/rust/src/plugin.rs +++ b/rust/src/plugin.rs @@ -19,9 +19,9 @@ pub fn init() { unsafe { - let context = super::core::SCGetContext(); - super::core::init_ffi(context); + let context = crate::core::SCGetContext(); + crate::core::init_ffi(context); - super::debug::SCSetRustLogLevel(super::debug::SCLogGetLogLevel()); + crate::debug::LEVEL = crate::debug::SCLogGetLogLevel(); } } From c6126b166b02636cda0311beec0f9d987d0d3f13 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 13:50:16 -0600 Subject: [PATCH 4/4] rust/plugins: expose eve plugin registration to Rust This allow for an EVE file type plugin written in Rust to register itself without needing to provide its own Rust bindings. --- rust/src/ffi/eve.rs | 79 +++++++++++++++++++++++++++++++++++++++++++ rust/src/ffi/mod.rs | 1 + rust/src/plugin.rs | 30 ++++++++++++++++ src/output-eve.h | 3 ++ src/suricata-plugin.h | 2 ++ 5 files changed, 115 insertions(+) create mode 100644 rust/src/ffi/eve.rs diff --git a/rust/src/ffi/eve.rs b/rust/src/ffi/eve.rs new file mode 100644 index 000000000000..f4f395960fb2 --- /dev/null +++ b/rust/src/ffi/eve.rs @@ -0,0 +1,79 @@ +/* Copyright (C) 2025 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +//! Bindings to Suricata C EVE related functions such as creating a +//! filetype. + +use std::ffi::{c_char, c_int, c_void, CString}; + +/// cbindgen:ignore +extern "C" { + pub fn SCRegisterEveFileType(filetype: *const EveFileType) -> bool; +} + +pub type EveFileInitFn = + unsafe extern "C" fn(conf: *const c_void, threaded: bool, init_data: *mut *mut c_void) -> c_int; +pub type EveFileDeinitFn = unsafe extern "C" fn(init_data: *const c_void); +pub type EveFileWriteFn = unsafe extern "C" fn( + buffer: *const c_char, + buffer_len: c_int, + init_data: *const c_void, + thread_data: *const c_void, +) -> c_int; +pub type EveFileThreadInitFn = unsafe extern "C" fn( + init_data: *const c_void, + thread_id: std::os::raw::c_int, + thread_data: *mut *mut c_void, +) -> c_int; +pub type EveFileThreadDeinitFn = + unsafe extern "C" fn(init_data: *const c_void, thread_data: *mut c_void); + +/// Rust equivalent to C SCEveFileType. +/// +/// NOTE: Needs to be kept in sync with SCEveFileType. +/// +/// cbindgen:ignore +#[repr(C)] +pub struct EveFileType { + name: *const c_char, + open: EveFileInitFn, + thread_init: EveFileThreadInitFn, + write: EveFileWriteFn, + thread_deinit: EveFileThreadDeinitFn, + close: EveFileDeinitFn, + pad: [usize; 2], +} + +impl EveFileType { + pub fn new( + name: &str, open: EveFileInitFn, close: EveFileDeinitFn, write: EveFileWriteFn, + thread_init: EveFileThreadInitFn, thread_deinit: EveFileThreadDeinitFn, + ) -> *const Self { + // Convert the name to C and forget. + let name = CString::new(name).unwrap().into_raw(); + let file_type = Self { + name, + open, + close, + write, + thread_init, + thread_deinit, + pad: [0, 0], + }; + Box::into_raw(Box::new(file_type)) + } +} diff --git a/rust/src/ffi/mod.rs b/rust/src/ffi/mod.rs index e97e6c98c639..5c61d3f1ad8a 100644 --- a/rust/src/ffi/mod.rs +++ b/rust/src/ffi/mod.rs @@ -20,3 +20,4 @@ pub mod hashing; pub mod base64; pub mod strings; +pub mod eve; diff --git a/rust/src/plugin.rs b/rust/src/plugin.rs index db47131848e5..89b9944ecb38 100644 --- a/rust/src/plugin.rs +++ b/rust/src/plugin.rs @@ -17,6 +17,36 @@ //! Plugin utility module. +use std::ffi::{c_char, CString}; + +/// Rust representation of a C plugin. +/// +/// Mirror of SCPlugin from C and they should be kept in sync. +#[repr(C)] +pub struct SCPlugin { + name: *const c_char, + license: *const c_char, + author: *const c_char, + init: unsafe extern "C" fn(), +} + +impl SCPlugin { + pub fn new( + name: &str, license: &str, author: &str, init_fn: unsafe extern "C" fn(), + ) -> *const Self { + let name = CString::new(name).unwrap(); + let license = CString::new(license).unwrap(); + let author = CString::new(author).unwrap(); + let plugin = SCPlugin { + name: name.into_raw(), + license: license.into_raw(), + author: author.into_raw(), + init: init_fn, + }; + Box::into_raw(Box::new(plugin)) + } +} + pub fn init() { unsafe { let context = crate::core::SCGetContext(); diff --git a/src/output-eve.h b/src/output-eve.h index 7e55ce28f8e2..d6635e2a545f 100644 --- a/src/output-eve.h +++ b/src/output-eve.h @@ -70,6 +70,9 @@ typedef uint32_t ThreadId; * may be naturally thread safe. However, if sharing a single file * handle across all threads then your filetype will have to take care * of locking, etc. + * + * NOTE: This data structure needs to be kept in sync with the Rust + * mirror of it in rust/src/ffi/eve.rs. */ typedef struct SCEveFileType_ { /** diff --git a/src/suricata-plugin.h b/src/suricata-plugin.h index 8bc2183d70fd..8bc245c28bda 100644 --- a/src/suricata-plugin.h +++ b/src/suricata-plugin.h @@ -31,6 +31,8 @@ /** * Structure to define a Suricata plugin. + * + * Needs to be kept in sync with SCPlugin in Rust as well. */ typedef struct SCPlugin_ { const char *name;