bgpkit_parser/models/bgp/flowspec/
operators.rs

1use super::FlowSpecError;
2
3/// Numeric operator for Flow-Spec components (RFC 8955 Section 4.2.1)
4#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct NumericOperator {
7    /// End-of-list flag (bit 7)
8    pub end_of_list: bool,
9    /// AND flag - true=AND with next, false=OR with next (bit 6)
10    pub and_with_next: bool,
11    /// Value length in octets (bits 5-4): 00=1, 01=2, 10=4, 11=8
12    pub value_length: u8,
13    /// Less-than comparison (bit 2)
14    pub less_than: bool,
15    /// Greater-than comparison (bit 1)
16    pub greater_than: bool,
17    /// Equal comparison (bit 0)
18    pub equal: bool,
19    /// The comparison value
20    pub value: u64,
21}
22
23/// Bitmask operator for Flow-Spec components (RFC 8955 Section 4.2.2)
24#[derive(Debug, Clone, PartialEq, Eq)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct BitmaskOperator {
27    /// End-of-list flag (bit 7)
28    pub end_of_list: bool,
29    /// AND flag - true=AND with next, false=OR with next (bit 6)
30    pub and_with_next: bool,
31    /// Value length in octets (bits 5-4): 00=1, 01=2, 10=4, 11=8
32    pub value_length: u8,
33    /// NOT flag - logical negation (bit 1)
34    pub not: bool,
35    /// Match flag - true=partial match, false=exact match (bit 0)
36    pub match_flag: bool,
37    /// The bitmask value
38    pub bitmask: u64,
39}
40
41impl NumericOperator {
42    /// Create a new numeric operator from raw byte and value
43    pub fn from_byte_and_value(operator_byte: u8, value: u64) -> Result<Self, FlowSpecError> {
44        let value_length = match (operator_byte >> 4) & 0x03 {
45            0 => 1,
46            1 => 2,
47            2 => 4,
48            3 => 8,
49            _ => return Err(FlowSpecError::InvalidOperator(operator_byte)),
50        };
51
52        // Bit 3 must be 0 for numeric operators
53        if (operator_byte & 0x08) != 0 {
54            return Err(FlowSpecError::InvalidOperator(operator_byte));
55        }
56
57        Ok(NumericOperator {
58            end_of_list: (operator_byte & 0x80) != 0,
59            and_with_next: (operator_byte & 0x40) != 0,
60            value_length,
61            less_than: (operator_byte & 0x04) != 0,
62            greater_than: (operator_byte & 0x02) != 0,
63            equal: (operator_byte & 0x01) != 0,
64            value,
65        })
66    }
67
68    /// Convert to byte representation
69    pub fn to_byte(&self) -> u8 {
70        let mut byte = 0u8;
71
72        if self.end_of_list {
73            byte |= 0x80;
74        }
75        if self.and_with_next {
76            byte |= 0x40;
77        }
78
79        // Encode length
80        let len_bits = match self.value_length {
81            1 => 0x00,
82            2 => 0x10,
83            4 => 0x20,
84            8 => 0x30,
85            _ => 0x00, // Default to 1 byte
86        };
87        byte |= len_bits;
88
89        // Bit 3 is reserved (0)
90
91        if self.less_than {
92            byte |= 0x04;
93        }
94        if self.greater_than {
95            byte |= 0x02;
96        }
97        if self.equal {
98            byte |= 0x01;
99        }
100
101        byte
102    }
103
104    /// Create equality operator
105    pub fn equal_to(value: u64) -> Self {
106        let value_length = if value <= 0xFF {
107            1
108        } else if value <= 0xFFFF {
109            2
110        } else if value <= 0xFFFFFFFF {
111            4
112        } else {
113            8
114        };
115
116        NumericOperator {
117            end_of_list: true,
118            and_with_next: false,
119            value_length,
120            less_than: false,
121            greater_than: false,
122            equal: true,
123            value,
124        }
125    }
126
127    /// Create range operator (greater than or equal)
128    pub fn greater_than_or_equal(value: u64) -> Self {
129        let value_length = if value <= 0xFF {
130            1
131        } else if value <= 0xFFFF {
132            2
133        } else if value <= 0xFFFFFFFF {
134            4
135        } else {
136            8
137        };
138
139        NumericOperator {
140            end_of_list: true,
141            and_with_next: false,
142            value_length,
143            less_than: false,
144            greater_than: true,
145            equal: true,
146            value,
147        }
148    }
149}
150
151impl BitmaskOperator {
152    /// Create a new bitmask operator from raw byte and value
153    pub fn from_byte_and_value(operator_byte: u8, bitmask: u64) -> Result<Self, FlowSpecError> {
154        let value_length = match (operator_byte >> 4) & 0x03 {
155            0 => 1,
156            1 => 2,
157            2 => 4,
158            3 => 8,
159            _ => return Err(FlowSpecError::InvalidOperator(operator_byte)),
160        };
161
162        // Bits 3 and 2 must be 0 for bitmask operators
163        if (operator_byte & 0x0C) != 0 {
164            return Err(FlowSpecError::InvalidOperator(operator_byte));
165        }
166
167        Ok(BitmaskOperator {
168            end_of_list: (operator_byte & 0x80) != 0,
169            and_with_next: (operator_byte & 0x40) != 0,
170            value_length,
171            not: (operator_byte & 0x02) != 0,
172            match_flag: (operator_byte & 0x01) != 0,
173            bitmask,
174        })
175    }
176
177    /// Convert to byte representation
178    pub fn to_byte(&self) -> u8 {
179        let mut byte = 0u8;
180
181        if self.end_of_list {
182            byte |= 0x80;
183        }
184        if self.and_with_next {
185            byte |= 0x40;
186        }
187
188        // Encode length
189        let len_bits = match self.value_length {
190            1 => 0x00,
191            2 => 0x10,
192            4 => 0x20,
193            8 => 0x30,
194            _ => 0x00, // Default to 1 byte
195        };
196        byte |= len_bits;
197
198        // Bits 3 and 2 are reserved (0)
199
200        if self.not {
201            byte |= 0x02;
202        }
203        if self.match_flag {
204            byte |= 0x01;
205        }
206
207        byte
208    }
209
210    /// Create exact match operator
211    pub fn exact_match(bitmask: u64) -> Self {
212        let value_length = if bitmask <= 0xFF {
213            1
214        } else if bitmask <= 0xFFFF {
215            2
216        } else if bitmask <= 0xFFFFFFFF {
217            4
218        } else {
219            8
220        };
221
222        BitmaskOperator {
223            end_of_list: true,
224            and_with_next: false,
225            value_length,
226            not: false,
227            match_flag: false,
228            bitmask,
229        }
230    }
231
232    /// Create partial match operator
233    pub fn partial_match(bitmask: u64) -> Self {
234        let value_length = if bitmask <= 0xFF {
235            1
236        } else if bitmask <= 0xFFFF {
237            2
238        } else if bitmask <= 0xFFFFFFFF {
239            4
240        } else {
241            8
242        };
243
244        BitmaskOperator {
245            end_of_list: true,
246            and_with_next: false,
247            value_length,
248            not: false,
249            match_flag: true,
250            bitmask,
251        }
252    }
253}
254
255#[cfg(test)]
256mod tests {
257    use super::*;
258
259    #[test]
260    fn test_numeric_operator_creation() {
261        let op = NumericOperator::equal_to(25);
262        assert!(op.equal);
263        assert!(!op.less_than);
264        assert!(!op.greater_than);
265        assert_eq!(op.value, 25);
266        assert_eq!(op.value_length, 1);
267    }
268
269    #[test]
270    fn test_numeric_operator_byte_conversion() {
271        let op = NumericOperator {
272            end_of_list: true,
273            and_with_next: false,
274            value_length: 1,
275            less_than: false,
276            greater_than: false,
277            equal: true,
278            value: 25,
279        };
280
281        let byte = op.to_byte();
282        assert_eq!(byte, 0x81); // 10000001: end_of_list=1, len=00, eq=1
283
284        let parsed_op = NumericOperator::from_byte_and_value(byte, 25).unwrap();
285        assert_eq!(parsed_op.end_of_list, op.end_of_list);
286        assert_eq!(parsed_op.equal, op.equal);
287        assert_eq!(parsed_op.value, op.value);
288    }
289
290    #[test]
291    fn test_bitmask_operator_creation() {
292        let op = BitmaskOperator::exact_match(0x06); // TCP SYN+FIN flags
293        assert!(!op.match_flag);
294        assert!(!op.not);
295        assert_eq!(op.bitmask, 0x06);
296        assert_eq!(op.value_length, 1);
297    }
298
299    #[test]
300    fn test_invalid_operator_byte() {
301        // Bit 3 should be 0 for numeric operators
302        let result = NumericOperator::from_byte_and_value(0x08, 25);
303        assert!(matches!(result, Err(FlowSpecError::InvalidOperator(0x08))));
304
305        // Bits 3 and 2 should be 0 for bitmask operators
306        let result = BitmaskOperator::from_byte_and_value(0x0C, 25);
307        assert!(matches!(result, Err(FlowSpecError::InvalidOperator(0x0C))));
308    }
309
310    #[test]
311    fn test_numeric_operator_various_lengths() {
312        // Test 1-byte value
313        let op1 = NumericOperator::equal_to(255);
314        assert_eq!(op1.value_length, 1);
315        assert_eq!(op1.value, 255);
316
317        // Test 2-byte value
318        let op2 = NumericOperator::equal_to(256);
319        assert_eq!(op2.value_length, 2);
320        assert_eq!(op2.value, 256);
321
322        // Test 4-byte value
323        let op4 = NumericOperator::equal_to(0x10000);
324        assert_eq!(op4.value_length, 4);
325        assert_eq!(op4.value, 0x10000);
326
327        // Test 8-byte value
328        let op8 = NumericOperator::equal_to(0x100000000);
329        assert_eq!(op8.value_length, 8);
330        assert_eq!(op8.value, 0x100000000);
331    }
332
333    #[test]
334    fn test_bitmask_operator_various_lengths() {
335        // Test 1-byte value
336        let op1 = BitmaskOperator::exact_match(255);
337        assert_eq!(op1.value_length, 1);
338        assert_eq!(op1.bitmask, 255);
339
340        // Test 2-byte value
341        let op2 = BitmaskOperator::exact_match(256);
342        assert_eq!(op2.value_length, 2);
343        assert_eq!(op2.bitmask, 256);
344
345        // Test 4-byte value
346        let op4 = BitmaskOperator::exact_match(0x10000);
347        assert_eq!(op4.value_length, 4);
348        assert_eq!(op4.bitmask, 0x10000);
349
350        // Test 8-byte value
351        let op8 = BitmaskOperator::exact_match(0x100000000);
352        assert_eq!(op8.value_length, 8);
353        assert_eq!(op8.bitmask, 0x100000000);
354    }
355
356    #[test]
357    fn test_numeric_operator_greater_than_or_equal() {
358        let op = NumericOperator::greater_than_or_equal(1000);
359        assert!(op.greater_than);
360        assert!(op.equal);
361        assert!(!op.less_than);
362        assert!(op.end_of_list);
363        assert!(!op.and_with_next);
364        assert_eq!(op.value, 1000);
365        assert_eq!(op.value_length, 2);
366    }
367
368    #[test]
369    fn test_bitmask_operator_partial_match() {
370        let op = BitmaskOperator::partial_match(0x06);
371        assert!(op.match_flag);
372        assert!(!op.not);
373        assert!(op.end_of_list);
374        assert!(!op.and_with_next);
375        assert_eq!(op.bitmask, 0x06);
376        assert_eq!(op.value_length, 1);
377    }
378
379    #[test]
380    fn test_numeric_operator_complex_byte_encoding() {
381        // Test complex operator: not end of list, AND with next, 2-byte length, less than + equal
382        let op = NumericOperator {
383            end_of_list: false,
384            and_with_next: true,
385            value_length: 2,
386            less_than: true,
387            greater_than: false,
388            equal: true,
389            value: 443,
390        };
391
392        let byte = op.to_byte();
393        // Expected: 0101 0101 = 0x55 (not_end=0, and=1, len=01, reserved=0, lt=1, gt=0, eq=1)
394        assert_eq!(byte, 0x55);
395
396        let parsed_op = NumericOperator::from_byte_and_value(byte, 443).unwrap();
397        assert_eq!(parsed_op.end_of_list, op.end_of_list);
398        assert_eq!(parsed_op.and_with_next, op.and_with_next);
399        assert_eq!(parsed_op.value_length, op.value_length);
400        assert_eq!(parsed_op.less_than, op.less_than);
401        assert_eq!(parsed_op.greater_than, op.greater_than);
402        assert_eq!(parsed_op.equal, op.equal);
403        assert_eq!(parsed_op.value, op.value);
404    }
405
406    #[test]
407    fn test_bitmask_operator_complex_byte_encoding() {
408        // Test complex operator: not end of list, AND with next, 4-byte length, NOT, partial match
409        let op = BitmaskOperator {
410            end_of_list: false,
411            and_with_next: true,
412            value_length: 4,
413            not: true,
414            match_flag: true,
415            bitmask: 0xFF000000,
416        };
417
418        let byte = op.to_byte();
419        // Expected: 0110 0011 = 0x63 (not_end=0, and=1, len=10, reserved=00, not=1, match=1)
420        assert_eq!(byte, 0x63);
421
422        let parsed_op = BitmaskOperator::from_byte_and_value(byte, 0xFF000000).unwrap();
423        assert_eq!(parsed_op.end_of_list, op.end_of_list);
424        assert_eq!(parsed_op.and_with_next, op.and_with_next);
425        assert_eq!(parsed_op.value_length, op.value_length);
426        assert_eq!(parsed_op.not, op.not);
427        assert_eq!(parsed_op.match_flag, op.match_flag);
428        assert_eq!(parsed_op.bitmask, op.bitmask);
429    }
430
431    #[test]
432    fn test_operator_invalid_length_defaults() {
433        // Test that invalid value lengths default to 1 byte in to_byte()
434        let mut op = NumericOperator::equal_to(25);
435        op.value_length = 7; // Invalid length
436        let byte = op.to_byte();
437        // Should default to 1-byte encoding (len bits = 00)
438        assert_eq!(byte & 0x30, 0x00);
439
440        let mut bm_op = BitmaskOperator::exact_match(25);
441        bm_op.value_length = 9; // Invalid length
442        let byte = bm_op.to_byte();
443        // Should default to 1-byte encoding (len bits = 00)
444        assert_eq!(byte & 0x30, 0x00);
445    }
446
447    #[test]
448    fn test_numeric_operator_all_comparison_flags() {
449        // Test operator with all comparison flags set
450        let op = NumericOperator {
451            end_of_list: true,
452            and_with_next: false,
453            value_length: 1,
454            less_than: true,
455            greater_than: true,
456            equal: true,
457            value: 100,
458        };
459
460        let byte = op.to_byte();
461        assert_eq!(byte, 0x87); // 10000111: end=1, len=00, lt=1, gt=1, eq=1
462
463        let parsed_op = NumericOperator::from_byte_and_value(byte, 100).unwrap();
464        assert!(parsed_op.less_than);
465        assert!(parsed_op.greater_than);
466        assert!(parsed_op.equal);
467    }
468
469    #[test]
470    fn test_bitmask_operator_edge_cases() {
471        // Test various combinations of NOT and match flags
472        let op_not_exact = BitmaskOperator {
473            end_of_list: true,
474            and_with_next: false,
475            value_length: 1,
476            not: true,
477            match_flag: false,
478            bitmask: 0x42,
479        };
480
481        let byte = op_not_exact.to_byte();
482        assert_eq!(byte, 0x82); // 10000010: end=1, len=00, not=1, match=0
483
484        let parsed_op = BitmaskOperator::from_byte_and_value(byte, 0x42).unwrap();
485        assert!(parsed_op.not);
486        assert!(!parsed_op.match_flag);
487    }
488
489    #[test]
490    fn test_operator_length_encoding_all_values() {
491        // Test all valid length encodings for numeric operators
492        for (expected_len, len_bits) in [(1, 0x00), (2, 0x10), (4, 0x20), (8, 0x30)] {
493            let op = NumericOperator {
494                end_of_list: true,
495                and_with_next: false,
496                value_length: expected_len,
497                less_than: false,
498                greater_than: false,
499                equal: true,
500                value: 42,
501            };
502
503            let byte = op.to_byte();
504            assert_eq!(byte & 0x30, len_bits);
505
506            let parsed_op = NumericOperator::from_byte_and_value(byte, 42).unwrap();
507            assert_eq!(parsed_op.value_length, expected_len);
508        }
509
510        // Test all valid length encodings for bitmask operators
511        for (expected_len, len_bits) in [(1, 0x00), (2, 0x10), (4, 0x20), (8, 0x30)] {
512            let op = BitmaskOperator {
513                end_of_list: true,
514                and_with_next: false,
515                value_length: expected_len,
516                not: false,
517                match_flag: true,
518                bitmask: 42,
519            };
520
521            let byte = op.to_byte();
522            assert_eq!(byte & 0x30, len_bits);
523
524            let parsed_op = BitmaskOperator::from_byte_and_value(byte, 42).unwrap();
525            assert_eq!(parsed_op.value_length, expected_len);
526        }
527    }
528}