Skip to main content

Engine

Struct Engine 

Source
pub struct Engine { /* private fields */ }
Expand description

The main rule evaluation engine.

Holds a set of compiled rules and provides methods to evaluate events against them. Supports optional logsource routing for performance.

§Example

use rsigma_parser::parse_sigma_yaml;
use rsigma_eval::{Engine, Event};
use rsigma_eval::event::JsonEvent;
use serde_json::json;

let yaml = r#"
title: Detect Whoami
logsource:
    product: windows
    category: process_creation
detection:
    selection:
        CommandLine|contains: 'whoami'
    condition: selection
level: medium
"#;

let collection = parse_sigma_yaml(yaml).unwrap();
let mut engine = Engine::new();
engine.add_collection(&collection).unwrap();

let event_val = json!({"CommandLine": "cmd /c whoami"});
let event = JsonEvent::borrow(&event_val);
let matches = engine.evaluate(&event);
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].rule_title, "Detect Whoami");

Implementations§

Source§

impl Engine

Source

pub fn new() -> Self

Create a new empty engine.

Source

pub fn new_with_pipeline(pipeline: Pipeline) -> Self

Create a new engine with a pipeline.

Source

pub fn set_bloom_prefilter(&mut self, enabled: bool)

Enable or disable bloom-filter pre-filtering of positive substring detection items.

When enabled, evaluate* short-circuits any positive substring matcher (Contains / StartsWith / EndsWith / AhoCorasickSet, alone or wrapped in CaseInsensitiveGroup) whose field cannot possibly contain a needle trigram.

Disabled by default. The per-event probe (trigram extraction + double hashing) costs ~1 µs on a typical CommandLine field, which outweighs the savings on rule sets where most events overlap with at least one needle. Enable for workloads that pair many substring rules with mostly-non-matching events; benchmark with eval_bloom_rejection before flipping it on in production.

Source

pub fn bloom_prefilter_enabled(&self) -> bool

Returns whether bloom pre-filtering is currently enabled.

Source

pub fn set_bloom_max_bytes(&mut self, max_bytes: usize)

Set the memory budget for the per-field bloom index.

Must be called before add_collection / add_rule for the new budget to take effect on the existing rule set; otherwise it is applied at the next index rebuild. The default budget is 1 MB, shared across all per-field filters. Lower the cap on memory- constrained deployments; raise it for large rule sets where the default starts evicting useful filters.

Source

pub fn bloom_max_bytes(&self) -> Option<usize>

Returns the configured bloom memory budget, if one has been set explicitly. None means the crate default (1 MB) is in use.

Source

pub fn set_include_event(&mut self, include: bool)

Set global include_event — when true, all match results include the full event JSON regardless of per-rule custom attributes.

Source

pub fn add_pipeline(&mut self, pipeline: Pipeline)

Add a pipeline to the engine.

Pipelines are applied to rules during add_rule / add_collection. Only affects rules added after this call.

Source

pub fn add_rule(&mut self, rule: &SigmaRule) -> Result<()>

Add a single parsed Sigma rule.

If pipelines are set, the rule is cloned and transformed before compilation. The rule index folds the new rule incrementally; the bloom index also folds it incrementally and only triggers a full rebuild when its doubling watermark is reached, so this call is amortized O(1) per rule. With the daachorse-index feature enabled and the cross-rule AC index turned on at runtime, the call falls back to a full rebuild because the daachorse automaton has no incremental update path.

Source

pub fn add_rules<'a, I>(&mut self, rules: I) -> Vec<(usize, EvalError)>
where I: IntoIterator<Item = &'a SigmaRule>,

Add many parsed Sigma rules in a single batch.

Each rule is compiled (with the engine’s pipelines applied, if any) and pushed onto the rule set. Compilation errors are collected and returned as (rule_index_in_input, error) pairs without aborting the batch; rules that did compile remain loaded. The inverted index and per-field bloom filter are rebuilt once at the end of the batch.

Prefer this over a loop of Engine::add_rule when loading large rule sets: the per-call rebuild is O(N) in the total rule count, so per-rule adds turn a 3K-rule corpus into O(N²) work.

Source

pub fn add_collection(&mut self, collection: &SigmaCollection) -> Result<()>

Add all detection rules from a parsed collection, then apply filters.

Filter rules modify referenced detection rules by appending exclusion conditions. Correlation rules are handled by CorrelationEngine. The inverted index is rebuilt once after all rules and filters are loaded.

Source

pub fn add_collection_with_pipelines( &mut self, collection: &SigmaCollection, pipelines: &[Pipeline], ) -> Result<()>

Add all detection rules from a collection, applying the given pipelines.

This is a convenience method that temporarily sets pipelines, adds the collection, then clears them. The inverted index is rebuilt once after all rules and filters are loaded.

Source

pub fn apply_filter(&mut self, filter: &FilterRule) -> Result<()>

Apply a filter rule to all referenced detection rules and rebuild the index.

Source

pub fn add_compiled_rule(&mut self, rule: CompiledRule)

Add a pre-compiled rule directly. The rule index folds the new rule incrementally; the bloom index also folds it incrementally and only triggers a full rebuild when its doubling watermark is reached, so this call is amortized O(1) per rule. With the cross-rule AC index enabled (daachorse-index feature, runtime toggle), this falls back to a full rebuild because daachorse has no incremental update path.

Source

pub fn extend_compiled_rules<I>(&mut self, rules: I)
where I: IntoIterator<Item = CompiledRule>,

Add many pre-compiled rules in a single batch. The inverted index and bloom filter are rebuilt exactly once at the end, regardless of how many rules are appended.

Source

pub fn evaluate<E: Event>(&self, event: &E) -> Vec<MatchResult>

Evaluate an event against candidate rules using the inverted index.

Source

pub fn evaluate_with_logsource<E: Event>( &self, event: &E, event_logsource: &LogSource, ) -> Vec<MatchResult>

Evaluate an event against candidate rules matching the given logsource.

Uses the inverted index for candidate pre-filtering, then applies the logsource constraint. Only rules whose logsource is compatible with event_logsource are evaluated.

Source

pub fn evaluate_batch<E: Event + Sync>( &self, events: &[&E], ) -> Vec<Vec<MatchResult>>

Evaluate a batch of events, returning per-event match results.

When the parallel feature is enabled, events are evaluated concurrently using rayon’s work-stealing thread pool. Otherwise, falls back to sequential evaluation.

Source

pub fn rule_count(&self) -> usize

Number of rules loaded in the engine.

Source

pub fn rules(&self) -> &[CompiledRule]

Access the compiled rules.

Trait Implementations§

Source§

impl Default for Engine

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.