1mod disruptive;
4mod flow;
5mod data;
6mod metadata;
7
8pub use disruptive::*;
9pub use flow::*;
10pub use data::*;
11pub use metadata::*;
12
13use crate::parser::{Action, DisruptiveAction, FlowAction, DataAction, MetadataAction, LoggingAction, SetVarValue};
14
15#[derive(Debug, Clone)]
17pub struct ActionResult {
18 pub disruptive: Option<DisruptiveOutcome>,
20 pub flow: FlowOutcome,
22 pub setvar_ops: Vec<SetVarOp>,
24 pub captures: Vec<String>,
26 pub metadata: RuleMetadata,
28}
29
30impl Default for ActionResult {
31 fn default() -> Self {
32 Self {
33 disruptive: None,
34 flow: FlowOutcome::Continue,
35 setvar_ops: Vec::new(),
36 captures: Vec::new(),
37 metadata: RuleMetadata::default(),
38 }
39 }
40}
41
42#[derive(Debug, Clone)]
44pub enum DisruptiveOutcome {
45 Deny(u16),
47 Block,
49 Allow,
51 Redirect(String),
53 Pass,
55 Drop,
57}
58
59#[derive(Debug, Clone, PartialEq)]
61pub enum FlowOutcome {
62 Continue,
64 Chain,
66 Skip(u32),
68 SkipAfter(String),
70}
71
72#[derive(Debug, Clone)]
74pub struct SetVarOp {
75 pub collection: String,
77 pub name: String,
79 pub operation: SetVarOperation,
81}
82
83#[derive(Debug, Clone)]
85pub enum SetVarOperation {
86 Set(String),
88 Increment(i64),
90 Decrement(i64),
92 Delete,
94}
95
96#[derive(Debug, Clone, Default)]
98pub struct RuleMetadata {
99 pub id: Option<String>,
101 pub msg: Option<String>,
103 pub logdata: Option<String>,
105 pub severity: Option<u8>,
107 pub tags: Vec<String>,
109 pub maturity: Option<u8>,
111 pub accuracy: Option<u8>,
113 pub rev: Option<String>,
115 pub ver: Option<String>,
117}
118
119pub fn execute_actions(
121 actions: &[Action],
122 matched_value: Option<&str>,
123 captures: &[String],
124) -> ActionResult {
125 let mut result = ActionResult::default();
126 result.captures = captures.to_vec();
127
128 for action in actions {
129 match action {
130 Action::Disruptive(d) => {
131 result.disruptive = Some(execute_disruptive(d));
132 }
133 Action::Flow(f) => {
134 result.flow = execute_flow(f);
135 }
136 Action::Data(d) => {
137 execute_data(d, &mut result, matched_value);
138 }
139 Action::Metadata(m) => {
140 execute_metadata(m, &mut result.metadata);
141 }
142 Action::Logging(l) => {
143 execute_logging(l, &mut result.metadata);
144 }
145 Action::Control(_) => {
146 }
148 Action::Transformation(_) => {
149 }
151 }
152 }
153
154 result
155}
156
157fn execute_disruptive(action: &DisruptiveAction) -> DisruptiveOutcome {
159 match action {
160 DisruptiveAction::Deny => DisruptiveOutcome::Deny(403),
161 DisruptiveAction::Block => DisruptiveOutcome::Block,
162 DisruptiveAction::Allow | DisruptiveAction::AllowPhase | DisruptiveAction::AllowRequest => {
163 DisruptiveOutcome::Allow
164 }
165 DisruptiveAction::Pass => DisruptiveOutcome::Pass,
166 DisruptiveAction::Drop => DisruptiveOutcome::Drop,
167 DisruptiveAction::Redirect(url) => DisruptiveOutcome::Redirect(url.clone()),
168 }
169}
170
171fn execute_flow(action: &FlowAction) -> FlowOutcome {
173 match action {
174 FlowAction::Chain => FlowOutcome::Chain,
175 FlowAction::Skip(n) => FlowOutcome::Skip(*n),
176 FlowAction::SkipAfter(marker) => FlowOutcome::SkipAfter(marker.clone()),
177 FlowAction::MultiMatch => FlowOutcome::Continue, }
179}
180
181fn execute_data(action: &DataAction, result: &mut ActionResult, _matched_value: Option<&str>) {
183 match action {
184 DataAction::Capture => {
185 }
187 DataAction::SetVar(spec) => {
188 let op = match &spec.value {
189 SetVarValue::String(v) => SetVarOperation::Set(v.clone()),
190 SetVarValue::Int(v) => SetVarOperation::Set(v.to_string()),
191 SetVarValue::Increment(v) => SetVarOperation::Increment(*v),
192 SetVarValue::Decrement(v) => SetVarOperation::Decrement(*v),
193 SetVarValue::Delete => SetVarOperation::Delete,
194 };
195 result.setvar_ops.push(SetVarOp {
196 collection: spec.collection.clone(),
197 name: spec.key.clone(),
198 operation: op,
199 });
200 }
201 DataAction::InitCol { .. } => {
202 }
204 DataAction::SetUid(_) => {
205 }
207 DataAction::SetSid(_) => {
208 }
210 DataAction::ExpireVar { .. } => {
211 }
213 DataAction::DeprecateVar(_) => {
214 }
216 DataAction::Exec(_) => {
217 }
219 DataAction::Prepend(_) | DataAction::Append(_) => {
220 }
222 }
223}
224
225fn execute_metadata(action: &MetadataAction, metadata: &mut RuleMetadata) {
227 match action {
228 MetadataAction::Id(id) => {
229 metadata.id = Some(id.to_string());
230 }
231 MetadataAction::Phase(_) => {
232 }
234 MetadataAction::Msg(msg) => {
235 metadata.msg = Some(msg.clone());
236 }
237 MetadataAction::Severity(sev) => {
238 metadata.severity = Some(*sev);
239 }
240 MetadataAction::Tag(tag) => {
241 metadata.tags.push(tag.clone());
242 }
243 MetadataAction::Maturity(m) => {
244 metadata.maturity = Some(*m);
245 }
246 MetadataAction::Accuracy(a) => {
247 metadata.accuracy = Some(*a);
248 }
249 MetadataAction::Rev(rev) => {
250 metadata.rev = Some(rev.clone());
251 }
252 MetadataAction::Ver(ver) => {
253 metadata.ver = Some(ver.clone());
254 }
255 MetadataAction::LogData(data) => {
256 metadata.logdata = Some(data.clone());
257 }
258 MetadataAction::Status(_) => {
259 }
261 }
262}
263
264fn execute_logging(action: &LoggingAction, _metadata: &mut RuleMetadata) {
266 match action {
267 LoggingAction::Log | LoggingAction::NoLog | LoggingAction::AuditLog | LoggingAction::NoAuditLog => {
268 }
270 LoggingAction::SanitiseMatched | LoggingAction::SanitizeMatched => {
271 }
273 LoggingAction::SanitiseArg(_)
274 | LoggingAction::SanitiseRequestHeader(_)
275 | LoggingAction::SanitiseResponseHeader(_) => {
276 }
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284 use crate::parser::{Action, DisruptiveAction, MetadataAction};
285
286 #[test]
287 fn test_execute_deny() {
288 let actions = vec![Action::Disruptive(DisruptiveAction::Deny)];
289 let result = execute_actions(&actions, None, &[]);
290 assert!(matches!(result.disruptive, Some(DisruptiveOutcome::Deny(403))));
291 }
292
293 #[test]
294 fn test_execute_metadata() {
295 let actions = vec![
296 Action::Metadata(MetadataAction::Id(12345)),
297 Action::Metadata(MetadataAction::Msg("Test rule".to_string())),
298 Action::Metadata(MetadataAction::Severity(2)),
299 Action::Metadata(MetadataAction::Tag("attack-sqli".to_string())),
300 ];
301 let result = execute_actions(&actions, None, &[]);
302 assert_eq!(result.metadata.id, Some("12345".to_string()));
303 assert_eq!(result.metadata.msg, Some("Test rule".to_string()));
304 assert_eq!(result.metadata.severity, Some(2));
305 assert_eq!(result.metadata.tags, vec!["attack-sqli".to_string()]);
306 }
307}