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 { ms: u64 },
147 Throttle { kbps: u64 },
149 Tag { key: String, value: String },
151 Inspect,
153 SetVariable { name: String, value: String },
155 RateLimit {
157 key: String,
159 limit: u32,
161 window_ms: u64,
163 },
164
165 RedirectIp {
167 target: String,
168 },
169 SetTtl {
170 ttl: u8,
171 },
172 ForwardPort {
173 target_host: String,
174 target_port: u16,
175 },
176
177 MockResponse {
180 status: u16,
181 headers: HashMap<String, String>,
182 body: Option<BodySource>,
183 },
184 MapLocal {
185 path: String,
186 content_type: Option<String>,
187 },
188 MapRemote {
189 url: String,
190 preserve_host: bool,
191 },
192 Redirect {
193 location: String,
194 status: u16,
195 },
196
197 AddRequestHeader {
200 name: String,
201 value: String,
202 },
203 UpdateRequestHeader {
206 name: String,
207 value: String,
208 add_if_missing: bool,
209 },
210 DeleteRequestHeader {
212 name: String,
213 },
214
215 AddResponseHeader {
216 name: String,
217 value: String,
218 },
219 UpdateResponseHeader {
220 name: String,
221 value: String,
222 add_if_missing: bool,
223 },
224 DeleteResponseHeader {
225 name: String,
226 },
227
228 SetRequestMethod {
230 method: String,
231 },
232 SetRequestUrl {
233 url: String,
234 },
235 SetRequestBody {
236 body: BodySource,
237 },
238 SetResponseStatus {
239 status: u16,
240 },
241 SetResponseBody {
242 body: BodySource,
243 },
244
245 TransformRequestBody {
247 transform: BodyTransform,
248 },
249 TransformResponseBody {
250 transform: BodyTransform,
251 },
252
253 MockWebSocketMessage {
255 direction: WebSocketDirection,
256 message: String,
257 },
258 DropWebSocketMessage,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262#[serde(tag = "type", content = "value")]
263pub enum BodySource {
264 Text(String),
265 File(String),
266 Base64(String),
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
270#[serde(tag = "type", content = "config")]
271pub enum BodyTransform {
272 RegexReplace { pattern: String, replacement: String },
273 JsonPathSet { path: String, value: String },
274 JsonPathDelete { path: String },
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub enum WebSocketDirection {
279 Incoming,
280 Outgoing,
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct RuleTrace {
287 pub flow_id: String,
288 pub summary: RuleTraceSummary,
290 pub events: Vec<RuleExecutionEvent>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
295pub enum RuleTraceSummary {
296 NoMatch,
297 Modified { rule_ids: Vec<String> },
299 Terminated {
301 rule_id: String,
302 reason: TerminalReason,
303 },
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
307pub enum TerminalReason {
308 Drop,
309 Abort,
310 Mock,
311 Redirect,
312 Inspect,
313 RateLimited,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct RuleExecutionEvent {
318 pub rule_id: String,
319 pub stage: RuleStage,
320 pub matched: bool,
321 pub duration_us: u64,
322 pub outcome: RuleOutcome,
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
326pub enum RuleOutcome {
327 Skipped,
328 MatchedAndExecuted,
329 MatchedAndTerminated,
330 Failed(String),
331}