Skip to main content

zentinel_modsec/engine/
mod.rs

1//! Transaction engine for ModSecurity rule processing.
2
3pub mod chain;
4pub mod control;
5pub mod intervention;
6pub mod phase;
7pub mod ruleset;
8pub mod scoring;
9pub mod transaction;
10
11pub use control::{CtlDirective, TransactionControls};
12pub use intervention::Intervention;
13pub use ruleset::{CompiledRuleset, Rules};
14pub use transaction::Transaction;
15
16use crate::error::Result;
17use std::sync::Arc;
18
19/// Main ModSecurity engine.
20pub struct ModSecurity {
21    /// Compiled ruleset.
22    ruleset: Arc<CompiledRuleset>,
23    /// Default block status code.
24    default_status: u16,
25}
26
27impl ModSecurity {
28    /// Create a new ModSecurity instance with the given ruleset.
29    pub fn new(ruleset: CompiledRuleset) -> Self {
30        Self {
31            ruleset: Arc::new(ruleset),
32            default_status: 403,
33        }
34    }
35
36    /// Load rules from a file.
37    pub fn from_file(path: &str) -> Result<Self> {
38        let ruleset = CompiledRuleset::from_file(path)?;
39        Ok(Self::new(ruleset))
40    }
41
42    /// Load rules from a string.
43    pub fn from_string(rules: &str) -> Result<Self> {
44        let ruleset = CompiledRuleset::from_string(rules)?;
45        Ok(Self::new(ruleset))
46    }
47
48    /// Set the default block status code.
49    pub fn set_default_status(&mut self, status: u16) {
50        self.default_status = status;
51    }
52
53    /// Create a new transaction for processing a request.
54    pub fn new_transaction(&self) -> Transaction {
55        Transaction::new(Arc::clone(&self.ruleset), self.default_status)
56    }
57
58    /// Get the ruleset.
59    pub fn ruleset(&self) -> &CompiledRuleset {
60        &self.ruleset
61    }
62
63    /// Get the number of rules.
64    pub fn rule_count(&self) -> usize {
65        self.ruleset.rule_count()
66    }
67}
68
69impl std::fmt::Debug for ModSecurity {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        f.debug_struct("ModSecurity")
72            .field("rule_count", &self.ruleset.rule_count())
73            .field("default_status", &self.default_status)
74            .finish()
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_modsec_from_string() {
84        let rules = r#"
85            SecRule REQUEST_URI "@contains /admin" "id:1,phase:1,deny"
86        "#;
87        let modsec = ModSecurity::from_string(rules).unwrap();
88        assert_eq!(modsec.rule_count(), 1);
89    }
90
91    #[test]
92    fn test_new_transaction() {
93        let rules = r#"
94            SecRule REQUEST_URI "@contains /admin" "id:1,phase:1,deny"
95        "#;
96        let modsec = ModSecurity::from_string(rules).unwrap();
97        let _tx = modsec.new_transaction();
98    }
99}