sentinel_modsec/parser/
directive.rs

1//! Directive types for ModSecurity configuration.
2
3use super::{Action, OperatorSpec, VariableSpec};
4use crate::error::SourceLocation;
5use std::path::PathBuf;
6
7/// A parsed ModSecurity directive.
8#[derive(Debug, Clone)]
9pub enum Directive {
10    /// SecRule directive - the main rule type.
11    SecRule(SecRule),
12    /// SecAction directive - actions without matching.
13    SecAction(SecAction),
14    /// SecMarker directive - named marker for skipAfter.
15    SecMarker(SecMarker),
16    /// SecRuleEngine directive - enable/disable rules.
17    SecRuleEngine(RuleEngineMode),
18    /// SecDefaultAction directive - default actions for rules.
19    SecDefaultAction(Vec<Action>),
20    /// SecRuleRemoveById directive - remove rules by ID.
21    SecRuleRemoveById(Vec<u64>),
22    /// SecRuleUpdateActionById directive - update rule actions.
23    SecRuleUpdateActionById { id: u64, actions: Vec<Action> },
24    /// SecRequestBodyAccess directive.
25    SecRequestBodyAccess(bool),
26    /// SecResponseBodyAccess directive.
27    SecResponseBodyAccess(bool),
28    /// SecRequestBodyLimit directive.
29    SecRequestBodyLimit(usize),
30    /// SecResponseBodyLimit directive.
31    SecResponseBodyLimit(usize),
32    /// Include directive - include another file.
33    Include(PathBuf),
34    /// Unknown directive (logged and skipped).
35    Unknown(String),
36}
37
38/// A SecRule directive.
39#[derive(Debug, Clone)]
40pub struct SecRule {
41    /// Variables to inspect.
42    pub variables: Vec<VariableSpec>,
43    /// Operator to apply.
44    pub operator: OperatorSpec,
45    /// Actions to execute on match.
46    pub actions: Vec<Action>,
47    /// Source location for error reporting.
48    pub location: SourceLocation,
49}
50
51/// A SecAction directive.
52#[derive(Debug, Clone)]
53pub struct SecAction {
54    /// Actions to execute.
55    pub actions: Vec<Action>,
56    /// Source location for error reporting.
57    pub location: SourceLocation,
58}
59
60/// A SecMarker directive.
61#[derive(Debug, Clone)]
62pub struct SecMarker {
63    /// Marker name.
64    pub name: String,
65}
66
67/// Rule engine mode.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum RuleEngineMode {
70    /// Rules are enabled and will block.
71    On,
72    /// Rules are disabled.
73    Off,
74    /// Rules are enabled but will only log, not block.
75    DetectionOnly,
76}
77
78impl Default for RuleEngineMode {
79    fn default() -> Self {
80        Self::Off
81    }
82}
83
84impl SecRule {
85    /// Check if this rule has the chain action.
86    pub fn is_chained(&self) -> bool {
87        self.actions.iter().any(|a| matches!(a, Action::Flow(super::FlowAction::Chain)))
88    }
89
90    /// Get the rule ID if present.
91    pub fn id(&self) -> Option<u64> {
92        for action in &self.actions {
93            if let Action::Metadata(super::MetadataAction::Id(id)) = action {
94                return Some(*id);
95            }
96        }
97        None
98    }
99
100    /// Get the phase for this rule (defaults to 2).
101    pub fn phase(&self) -> u8 {
102        for action in &self.actions {
103            if let Action::Metadata(super::MetadataAction::Phase(phase)) = action {
104                return *phase;
105            }
106        }
107        2 // Default phase is 2 (request body)
108    }
109}