diff --git a/rust/src/detect/requires.rs b/rust/src/detect/requires.rs index 05351757ac95..a1a61f2d87be 100644 --- a/rust/src/detect/requires.rs +++ b/rust/src/detect/requires.rs @@ -237,10 +237,10 @@ fn check_requires( } } - #[allow(clippy::never_loop)] - for _feature in &requires.features { - // TODO: Any feature is a missing feature for now. - return Err(RequiresError::MissingFeature); + for feature in &requires.features { + if !crate::feature::requires(feature) { + return Err(RequiresError::MissingFeature); + } } Ok(()) @@ -474,5 +474,10 @@ mod test { check_requires(&requires, &suricata_version), Err(RequiresError::MissingFeature) ); + + // Require feature foobar, but this time we have the feature. + let suricata_version = SuricataVersion::new(8, 0, 0); + let requires = parse_requires("feature true_foobar").unwrap().1; + assert_eq!(check_requires(&requires, &suricata_version), Ok(())); } } diff --git a/rust/src/feature.rs b/rust/src/feature.rs new file mode 100644 index 000000000000..abd09669af11 --- /dev/null +++ b/rust/src/feature.rs @@ -0,0 +1,60 @@ +/* Copyright (C) 2023 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. + */ + +//! Rust bindings to the "feature" API. +//! +//! As this feature module is a binding to a Suricata C module it is +//! not available to Rust unit tests. Instead when running Rust unit +//! tests and "mock" version is provided that will return true for any +//! feature starting with "true" and false for any other feature name. + +#[cfg(test)] +mod mock { + /// Check for a feature returning true if found. + /// + /// This a "mock" variant of `requires` that will return true for + /// any feature starting with string `true`, and false for + /// anything else. + pub fn requires(feature: &str) -> bool { + return feature.starts_with("true"); + } +} + +#[cfg(not(test))] +mod real { + use std::ffi::CString; + use std::os::raw::c_char; + + extern "C" { + fn RequiresFeature(feature: *const c_char) -> bool; + } + + /// Check for a feature returning true if found. + pub fn requires(feature: &str) -> bool { + if let Ok(feature) = CString::new(feature) { + unsafe { RequiresFeature(feature.as_ptr()) } + } else { + false + } + } +} + +#[cfg(not(test))] +pub use real::*; + +#[cfg(test)] +pub use mock::*; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index da2859637783..84b82bde19f7 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -116,3 +116,4 @@ pub mod plugin; pub mod lzma; pub mod util; pub mod ffi; +pub mod feature;