1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Rule {
7 pub id: String,
9 pub name: String,
11 pub active: bool,
13
14 pub stage: RuleStage,
16
17 #[serde(default)]
20 pub priority: i32,
21
22 pub termination: RuleTermination,
25
26 pub filter: Filter,
28
29 pub actions: Vec<Action>,
31
32 pub constraints: Option<RuleConstraints>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct RuleGroup {
38 pub id: String,
39 pub name: String,
40 pub active: bool,
41 pub rules: Vec<Rule>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub enum RuleStage {
46 Connect,
48 RequestHeaders,
50 RequestBody,
52 ResponseHeaders,
54 ResponseBody,
56 WebSocketMessage,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub enum RuleTermination {
62 Continue,
64 Stop,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct RuleConstraints {
70 pub timeout_ms: Option<u64>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(tag = "type", content = "config")]
78pub enum Filter {
79 All,
81
82 SrcIp(String), DstPort(u16),
87 Protocol(String),
89 TransparentMode(bool),
91
92 Url(StringMatcher),
95 Host(StringMatcher),
97 Path(StringMatcher),
99 Method(StringMatcher),
101 RequestHeader {
103 name: String,
104 value: Option<StringMatcher>,
105 },
106 ResponseHeader {
108 name: String,
109 value: Option<StringMatcher>,
110 },
111 StatusCode(u16),
113 ResponseBody(StringMatcher),
115 WebSocketMessage(StringMatcher),
117
118 And(Vec<Filter>),
120 Or(Vec<Filter>),
121 Not(Box<Filter>),
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[serde(tag = "mode", content = "value")]
126pub enum StringMatcher {
127 Exact(String),
128 Contains(String),
129 Prefix(String),
130 Suffix(String),
131 Regex(String),
132 Glob(String),
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(tag = "type", content = "config")]
139pub enum Action {
140 Drop,
143 Abort,
145 Delay {
147 ms: u64,
148 },
149 Throttle {
151 kbps: u64,
152 },
153 Tag {
155 key: String,
156 value: String,
157 },
158 Inspect,
160 SetVariable {
162 name: String,
163 value: String,
164 },
165 RateLimit {
167 key: String,
169 limit: u32,
171 window_ms: u64,
173 },
174
175 RedirectIp {
177 target: String,
178 },
179 SetTtl {
180 ttl: u8,
181 },
182 ForwardPort {
183 target_host: String,
184 target_port: u16,
185 },
186
187 MockResponse {
190 status: u16,
191 headers: HashMap<String, String>,
192 body: Option<BodySource>,
193 },
194 MapLocal {
195 path: String,
196 content_type: Option<String>,
197 },
198 MapRemote {
199 url: String,
200 preserve_host: bool,
201 },
202 Redirect {
203 location: String,
204 status: u16,
205 },
206
207 AddRequestHeader {
210 name: String,
211 value: String,
212 },
213 UpdateRequestHeader {
216 name: String,
217 value: String,
218 add_if_missing: bool,
219 },
220 DeleteRequestHeader {
222 name: String,
223 },
224
225 AddResponseHeader {
226 name: String,
227 value: String,
228 },
229 UpdateResponseHeader {
230 name: String,
231 value: String,
232 add_if_missing: bool,
233 },
234 DeleteResponseHeader {
235 name: String,
236 },
237
238 SetRequestMethod {
240 method: String,
241 },
242 SetRequestUrl {
243 url: String,
244 },
245 SetRequestBody {
246 body: BodySource,
247 },
248 SetResponseStatus {
249 status: u16,
250 },
251 SetResponseBody {
252 body: BodySource,
253 },
254
255 TransformRequestBody {
257 transform: BodyTransform,
258 },
259 TransformResponseBody {
260 transform: BodyTransform,
261 },
262
263 MockWebSocketMessage {
265 direction: WebSocketDirection,
266 message: String,
267 },
268 DropWebSocketMessage,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
272#[serde(tag = "type", content = "value")]
273pub enum BodySource {
274 Text(String),
275 File(String),
276 Base64(String),
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
280#[serde(tag = "type", content = "config")]
281pub enum BodyTransform {
282 RegexReplace {
283 pattern: String,
284 replacement: String,
285 },
286 JsonPathSet {
287 path: String,
288 value: String,
289 },
290 JsonPathDelete {
291 path: String,
292 },
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub enum WebSocketDirection {
297 Incoming,
298 Outgoing,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct RuleTrace {
305 pub flow_id: String,
306 pub summary: RuleTraceSummary,
308 pub events: Vec<RuleExecutionEvent>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
313pub enum RuleTraceSummary {
314 NoMatch,
315 Modified {
317 rule_ids: Vec<String>,
318 },
319 Terminated {
321 rule_id: String,
322 reason: TerminalReason,
323 },
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
327pub enum TerminalReason {
328 Drop,
329 Abort,
330 Mock,
331 Redirect,
332 Inspect,
333 RateLimited,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct RuleExecutionEvent {
338 pub rule_id: String,
339 pub stage: RuleStage,
340 pub matched: bool,
341 pub duration_us: u64,
342 pub outcome: RuleOutcome,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
346pub enum RuleOutcome {
347 Skipped,
348 MatchedAndExecuted,
349 MatchedAndTerminated,
350 Failed(String),
351}