pcapsql_core/protocol/
gre.rs

1//! GRE (Generic Routing Encapsulation) protocol parser.
2//!
3//! GRE is a tunneling protocol that can encapsulate a wide variety of
4//! network layer protocols inside virtual point-to-point links.
5//!
6//! RFC 2784: Generic Routing Encapsulation (GRE)
7//! RFC 2890: Key and Sequence Number Extensions to GRE
8//! RFC 2637: Point-to-Point Tunneling Protocol (PPTP) - Enhanced GRE (Version 1)
9
10use smallvec::SmallVec;
11
12use super::{FieldValue, ParseContext, ParseResult, Protocol, TunnelType};
13use crate::schema::{DataKind, FieldDescriptor};
14
15/// IP protocol number for GRE.
16pub const IP_PROTOCOL_GRE: u8 = 47;
17
18/// GRE version numbers.
19pub mod gre_version {
20    /// Standard GRE (RFC 2784/2890).
21    pub const STANDARD: u8 = 0;
22    /// Enhanced GRE for PPTP (RFC 2637).
23    pub const PPTP_ENHANCED: u8 = 1;
24}
25
26/// Calculate internet checksum over data.
27/// Returns the checksum value (0 indicates valid checksum when computed over data including checksum field).
28fn internet_checksum(data: &[u8]) -> u16 {
29    let mut sum: u32 = 0;
30    let mut i = 0;
31
32    // Sum 16-bit words
33    while i + 1 < data.len() {
34        sum += u16::from_be_bytes([data[i], data[i + 1]]) as u32;
35        i += 2;
36    }
37
38    // Handle odd byte
39    if i < data.len() {
40        sum += (data[i] as u32) << 8;
41    }
42
43    // Fold 32-bit sum to 16 bits
44    while sum >> 16 != 0 {
45        sum = (sum & 0xFFFF) + (sum >> 16);
46    }
47
48    !sum as u16
49}
50
51/// GRE protocol parser.
52#[derive(Debug, Clone, Copy)]
53pub struct GreProtocol;
54
55impl Protocol for GreProtocol {
56    fn name(&self) -> &'static str {
57        "gre"
58    }
59
60    fn display_name(&self) -> &'static str {
61        "GRE"
62    }
63
64    fn can_parse(&self, context: &ParseContext) -> Option<u32> {
65        // Match when IP protocol hint equals 47
66        match context.hint("ip_protocol") {
67            Some(proto) if proto == IP_PROTOCOL_GRE as u64 => Some(100),
68            _ => None,
69        }
70    }
71
72    fn parse<'a>(&self, data: &'a [u8], _context: &ParseContext) -> ParseResult<'a> {
73        // Minimum GRE header is 4 bytes (flags/version + protocol type)
74        if data.len() < 4 {
75            return ParseResult::error("GRE header too short".to_string(), data);
76        }
77
78        let mut fields = SmallVec::new();
79        let mut offset = 0;
80
81        // First 2 bytes: Flags and Version
82        // Bit 0: Checksum present (C)
83        // Bit 1: Reserved (R) - must be 0
84        // Bit 2: Key present (K)
85        // Bit 3: Sequence number present (S)
86        // Bits 4: Strict source route (s)
87        // Bits 5-7: Recursion control (Recur)
88        // Bits 8-12: Flags (A in bit 8, rest reserved)
89        // Bits 13-15: Version (0 for GRE, 1 for enhanced GRE)
90        let flags = u16::from_be_bytes([data[0], data[1]]);
91
92        let checksum_present = (flags & 0x8000) != 0;
93        let key_present = (flags & 0x2000) != 0;
94        let sequence_present = (flags & 0x1000) != 0;
95        let version = (flags & 0x0007) as u8;
96
97        fields.push(("checksum_present", FieldValue::Bool(checksum_present)));
98        fields.push(("key_present", FieldValue::Bool(key_present)));
99        fields.push(("sequence_present", FieldValue::Bool(sequence_present)));
100        fields.push(("version", FieldValue::UInt8(version)));
101
102        // Version validation (RFC 2784: Version MUST be 0, RFC 2637: Version 1 for PPTP)
103        let version_valid =
104            version == gre_version::STANDARD || version == gre_version::PPTP_ENHANCED;
105        fields.push(("version_valid", FieldValue::Bool(version_valid)));
106
107        // Add version name for convenience
108        let version_name = match version {
109            gre_version::STANDARD => "Standard",
110            gre_version::PPTP_ENHANCED => "PPTP-Enhanced",
111            _ => "Unknown",
112        };
113        fields.push(("version_name", FieldValue::Str(version_name)));
114
115        offset += 2;
116
117        // Next 2 bytes: Protocol Type (EtherType of encapsulated protocol)
118        let protocol_type = u16::from_be_bytes([data[offset], data[offset + 1]]);
119        fields.push(("protocol", FieldValue::UInt16(protocol_type)));
120        offset += 2;
121
122        // Track header length for checksum verification
123        let header_start = 0;
124
125        // Optional fields based on flags
126
127        // Checksum and Reserved (4 bytes if C bit set)
128        if checksum_present {
129            if data.len() < offset + 4 {
130                return ParseResult::error("GRE: missing checksum field".to_string(), data);
131            }
132            let checksum = u16::from_be_bytes([data[offset], data[offset + 1]]);
133            fields.push(("checksum", FieldValue::UInt16(checksum)));
134
135            // Calculate the end of GRE header + payload for checksum verification
136            // GRE checksum covers the GRE header and payload
137            // To verify: compute checksum over entire packet (with checksum field included)
138            // Result should be 0 if valid
139            let computed = internet_checksum(data);
140            let checksum_valid = computed == 0;
141            fields.push(("checksum_valid", FieldValue::Bool(checksum_valid)));
142
143            // Reserved field (offset) is at offset+2..offset+4, typically ignored
144            offset += 4;
145        }
146
147        // Key (4 bytes if K bit set)
148        let mut key_value: Option<u32> = None;
149        if key_present {
150            if data.len() < offset + 4 {
151                return ParseResult::error("GRE: missing key field".to_string(), data);
152            }
153            let key = u32::from_be_bytes([
154                data[offset],
155                data[offset + 1],
156                data[offset + 2],
157                data[offset + 3],
158            ]);
159            fields.push(("key", FieldValue::UInt32(key)));
160            key_value = Some(key);
161            offset += 4;
162        }
163
164        // Sequence Number (4 bytes if S bit set)
165        if sequence_present {
166            if data.len() < offset + 4 {
167                return ParseResult::error("GRE: missing sequence field".to_string(), data);
168            }
169            let sequence = u32::from_be_bytes([
170                data[offset],
171                data[offset + 1],
172                data[offset + 2],
173                data[offset + 3],
174            ]);
175            fields.push(("sequence", FieldValue::UInt32(sequence)));
176            offset += 4;
177        }
178
179        // Store header length
180        fields.push((
181            "header_length",
182            FieldValue::UInt8((offset - header_start) as u8),
183        ));
184
185        // Set up child hints for the encapsulated protocol
186        let mut child_hints = SmallVec::new();
187        child_hints.push(("ethertype", protocol_type as u64));
188
189        // If key is present, pass it as a hint for tunneling context
190        if let Some(key) = key_value {
191            child_hints.push(("gre_key", key as u64));
192        }
193
194        // Common ethertypes in GRE:
195        // ethertype::IPV4 = IPv4
196        // ethertype::IPV6 = IPv6
197        // 0x6558 = Transparent Ethernet Bridging (for NVGRE)
198        // 0x880B = PPP
199
200        // Signal tunnel boundary for encapsulation tracking
201        child_hints.push(("tunnel_type", TunnelType::Gre as u64));
202        // Use GRE key as tunnel ID if present
203        if let Some(key) = key_value {
204            child_hints.push(("tunnel_id", key as u64));
205        }
206
207        ParseResult::success(fields, &data[offset..], child_hints)
208    }
209
210    fn schema_fields(&self) -> Vec<FieldDescriptor> {
211        vec![
212            FieldDescriptor::new("gre.checksum_present", DataKind::Bool).set_nullable(true),
213            FieldDescriptor::new("gre.key_present", DataKind::Bool).set_nullable(true),
214            FieldDescriptor::new("gre.sequence_present", DataKind::Bool).set_nullable(true),
215            FieldDescriptor::new("gre.version", DataKind::UInt8).set_nullable(true),
216            FieldDescriptor::new("gre.version_valid", DataKind::Bool).set_nullable(true),
217            FieldDescriptor::new("gre.version_name", DataKind::String).set_nullable(true),
218            FieldDescriptor::new("gre.protocol", DataKind::UInt16).set_nullable(true),
219            FieldDescriptor::new("gre.checksum", DataKind::UInt16).set_nullable(true),
220            FieldDescriptor::new("gre.checksum_valid", DataKind::Bool).set_nullable(true),
221            FieldDescriptor::new("gre.key", DataKind::UInt32).set_nullable(true),
222            FieldDescriptor::new("gre.sequence", DataKind::UInt32).set_nullable(true),
223            FieldDescriptor::new("gre.header_length", DataKind::UInt8).set_nullable(true),
224        ]
225    }
226
227    fn child_protocols(&self) -> &[&'static str] {
228        // GRE can encapsulate many protocols
229        &["ipv4", "ipv6", "ethernet"]
230    }
231
232    fn dependencies(&self) -> &'static [&'static str] {
233        &["ipv4", "ipv6"] // GRE runs over IPv4/IPv6 (IP protocol 47)
234    }
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240    use crate::protocol::ethernet::ethertype;
241
242    /// Create a minimal GRE header with just flags and protocol type.
243    fn create_gre_header(checksum: bool, key: bool, sequence: bool, protocol: u16) -> Vec<u8> {
244        let mut header = Vec::new();
245
246        // Build flags word
247        let mut flags: u16 = 0;
248        if checksum {
249            flags |= 0x8000;
250        }
251        if key {
252            flags |= 0x2000;
253        }
254        if sequence {
255            flags |= 0x1000;
256        }
257        // Version = 0
258
259        header.extend_from_slice(&flags.to_be_bytes());
260        header.extend_from_slice(&protocol.to_be_bytes());
261
262        header
263    }
264
265    // Test 1: can_parse with IP protocol 47
266    #[test]
267    fn test_can_parse_with_ip_protocol_47() {
268        let parser = GreProtocol;
269
270        // Without hint
271        let ctx1 = ParseContext::new(1);
272        assert!(parser.can_parse(&ctx1).is_none());
273
274        // With wrong IP protocol
275        let mut ctx2 = ParseContext::new(1);
276        ctx2.insert_hint("ip_protocol", 6); // TCP
277        assert!(parser.can_parse(&ctx2).is_none());
278
279        // With GRE IP protocol
280        let mut ctx3 = ParseContext::new(1);
281        ctx3.insert_hint("ip_protocol", 47);
282        assert!(parser.can_parse(&ctx3).is_some());
283        assert_eq!(parser.can_parse(&ctx3), Some(100));
284    }
285
286    // Test 2: Basic GRE header parsing (no optional fields)
287    #[test]
288    fn test_basic_gre_header_parsing() {
289        let mut header = create_gre_header(false, false, false, ethertype::IPV4); // IPv4
290                                                                                  // Add some payload
291        header.extend_from_slice(&[0x45, 0x00, 0x00, 0x28]);
292
293        let parser = GreProtocol;
294        let mut context = ParseContext::new(1);
295        context.insert_hint("ip_protocol", 47);
296
297        let result = parser.parse(&header, &context);
298
299        assert!(result.is_ok());
300        assert_eq!(
301            result.get("checksum_present"),
302            Some(&FieldValue::Bool(false))
303        );
304        assert_eq!(result.get("key_present"), Some(&FieldValue::Bool(false)));
305        assert_eq!(
306            result.get("sequence_present"),
307            Some(&FieldValue::Bool(false))
308        );
309        assert_eq!(result.get("version"), Some(&FieldValue::UInt8(0)));
310        assert_eq!(
311            result.get("protocol"),
312            Some(&FieldValue::UInt16(ethertype::IPV4))
313        );
314
315        // Should not have optional fields
316        assert!(result.get("checksum").is_none());
317        assert!(result.get("key").is_none());
318        assert!(result.get("sequence").is_none());
319
320        // Remaining should be the payload
321        assert_eq!(result.remaining.len(), 4);
322    }
323
324    // Test 3: GRE with checksum
325    #[test]
326    fn test_gre_with_checksum() {
327        let mut header = create_gre_header(true, false, false, ethertype::IPV4);
328        // Add checksum (2 bytes) and reserved (2 bytes)
329        header.extend_from_slice(&[0xAB, 0xCD, 0x00, 0x00]);
330        // Add payload
331        header.extend_from_slice(&[0x45, 0x00]);
332
333        let parser = GreProtocol;
334        let mut context = ParseContext::new(1);
335        context.insert_hint("ip_protocol", 47);
336
337        let result = parser.parse(&header, &context);
338
339        assert!(result.is_ok());
340        assert_eq!(
341            result.get("checksum_present"),
342            Some(&FieldValue::Bool(true))
343        );
344        assert_eq!(result.get("checksum"), Some(&FieldValue::UInt16(0xABCD)));
345        assert_eq!(result.remaining.len(), 2);
346    }
347
348    // Test 4: GRE with key
349    #[test]
350    fn test_gre_with_key() {
351        let mut header = create_gre_header(false, true, false, ethertype::IPV4);
352        // Add key (4 bytes)
353        header.extend_from_slice(&[0x00, 0x01, 0x02, 0x03]);
354        // Add payload
355        header.extend_from_slice(&[0x45, 0x00]);
356
357        let parser = GreProtocol;
358        let mut context = ParseContext::new(1);
359        context.insert_hint("ip_protocol", 47);
360
361        let result = parser.parse(&header, &context);
362
363        assert!(result.is_ok());
364        assert_eq!(result.get("key_present"), Some(&FieldValue::Bool(true)));
365        assert_eq!(result.get("key"), Some(&FieldValue::UInt32(0x00010203)));
366        assert_eq!(result.hint("gre_key"), Some(0x00010203u64));
367        assert_eq!(result.remaining.len(), 2);
368    }
369
370    // Test 5: GRE with sequence number
371    #[test]
372    fn test_gre_with_sequence() {
373        let mut header = create_gre_header(false, false, true, ethertype::IPV4);
374        // Add sequence number (4 bytes)
375        header.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
376        // Add payload
377        header.extend_from_slice(&[0x45, 0x00]);
378
379        let parser = GreProtocol;
380        let mut context = ParseContext::new(1);
381        context.insert_hint("ip_protocol", 47);
382
383        let result = parser.parse(&header, &context);
384
385        assert!(result.is_ok());
386        assert_eq!(
387            result.get("sequence_present"),
388            Some(&FieldValue::Bool(true))
389        );
390        assert_eq!(
391            result.get("sequence"),
392            Some(&FieldValue::UInt32(0xDEADBEEF))
393        );
394        assert_eq!(result.remaining.len(), 2);
395    }
396
397    // Test 6: GRE with all optional fields
398    #[test]
399    fn test_gre_with_all_optional_fields() {
400        let mut header = create_gre_header(true, true, true, ethertype::IPV6); // IPv6
401                                                                               // Add checksum and reserved
402        header.extend_from_slice(&[0x12, 0x34, 0x00, 0x00]);
403        // Add key
404        header.extend_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]);
405        // Add sequence
406        header.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
407        // Add payload
408        header.extend_from_slice(&[0x60, 0x00]);
409
410        let parser = GreProtocol;
411        let mut context = ParseContext::new(1);
412        context.insert_hint("ip_protocol", 47);
413
414        let result = parser.parse(&header, &context);
415
416        assert!(result.is_ok());
417        assert_eq!(
418            result.get("checksum_present"),
419            Some(&FieldValue::Bool(true))
420        );
421        assert_eq!(result.get("key_present"), Some(&FieldValue::Bool(true)));
422        assert_eq!(
423            result.get("sequence_present"),
424            Some(&FieldValue::Bool(true))
425        );
426        assert_eq!(result.get("checksum"), Some(&FieldValue::UInt16(0x1234)));
427        assert_eq!(result.get("key"), Some(&FieldValue::UInt32(0xAABBCCDD)));
428        assert_eq!(result.get("sequence"), Some(&FieldValue::UInt32(1)));
429        assert_eq!(
430            result.get("protocol"),
431            Some(&FieldValue::UInt16(ethertype::IPV6))
432        );
433        assert_eq!(result.remaining.len(), 2);
434    }
435
436    // Test 7: Child protocol hint (ethertype)
437    #[test]
438    fn test_child_protocol_hint_ethertype() {
439        // Test IPv4 ethertype
440        let header_ipv4 = create_gre_header(false, false, false, ethertype::IPV4);
441        let parser = GreProtocol;
442        let mut context = ParseContext::new(1);
443        context.insert_hint("ip_protocol", 47);
444
445        let result = parser.parse(&header_ipv4, &context);
446        assert!(result.is_ok());
447        assert_eq!(result.hint("ethertype"), Some(ethertype::IPV4 as u64));
448
449        // Test IPv6 ethertype
450        let header_ipv6 = create_gre_header(false, false, false, ethertype::IPV6);
451        let result = parser.parse(&header_ipv6, &context);
452        assert!(result.is_ok());
453        assert_eq!(result.hint("ethertype"), Some(ethertype::IPV6 as u64));
454
455        // Test Transparent Ethernet Bridging
456        let header_teb = create_gre_header(false, false, false, 0x6558);
457        let result = parser.parse(&header_teb, &context);
458        assert!(result.is_ok());
459        assert_eq!(result.hint("ethertype"), Some(0x6558u64));
460    }
461
462    // Test 8: Too short header
463    #[test]
464    fn test_gre_too_short() {
465        let short_header = [0x00, 0x00]; // Only 2 bytes
466
467        let parser = GreProtocol;
468        let mut context = ParseContext::new(1);
469        context.insert_hint("ip_protocol", 47);
470
471        let result = parser.parse(&short_header, &context);
472        assert!(!result.is_ok());
473        assert!(result.error.is_some());
474    }
475
476    // Test 9: Missing optional fields when flags are set
477    #[test]
478    fn test_gre_missing_key_field() {
479        let header = create_gre_header(false, true, false, ethertype::IPV4); // Key flag set but no key data
480
481        let parser = GreProtocol;
482        let mut context = ParseContext::new(1);
483        context.insert_hint("ip_protocol", 47);
484
485        let result = parser.parse(&header, &context);
486        assert!(!result.is_ok());
487        assert!(result.error.unwrap().contains("missing key field"));
488    }
489
490    // Test 10: Schema fields
491    #[test]
492    fn test_gre_schema_fields() {
493        let parser = GreProtocol;
494        let fields = parser.schema_fields();
495
496        assert!(!fields.is_empty());
497        let field_names: Vec<&str> = fields.iter().map(|f| f.name).collect();
498        assert!(field_names.contains(&"gre.checksum_present"));
499        assert!(field_names.contains(&"gre.key_present"));
500        assert!(field_names.contains(&"gre.sequence_present"));
501        assert!(field_names.contains(&"gre.version"));
502        assert!(field_names.contains(&"gre.protocol"));
503        assert!(field_names.contains(&"gre.checksum"));
504        assert!(field_names.contains(&"gre.key"));
505        assert!(field_names.contains(&"gre.sequence"));
506    }
507
508    // Test 11: Version 0 (Standard GRE) validation
509    #[test]
510    fn test_version_0_standard_gre() {
511        let parser = GreProtocol;
512        let mut context = ParseContext::new(1);
513        context.insert_hint("ip_protocol", 47);
514
515        // Standard GRE with version 0
516        let header = create_gre_header(false, false, false, ethertype::IPV4);
517        let result = parser.parse(&header, &context);
518
519        assert!(result.is_ok());
520        assert_eq!(
521            result.get("version"),
522            Some(&FieldValue::UInt8(gre_version::STANDARD))
523        );
524        assert_eq!(result.get("version_valid"), Some(&FieldValue::Bool(true)));
525        assert_eq!(
526            result.get("version_name"),
527            Some(&FieldValue::Str("Standard"))
528        );
529    }
530
531    // Test 12: Version 1 (PPTP Enhanced GRE) validation
532    #[test]
533    fn test_version_1_pptp_enhanced() {
534        let parser = GreProtocol;
535        let mut context = ParseContext::new(1);
536        context.insert_hint("ip_protocol", 47);
537
538        // Create PPTP Enhanced GRE (version 1) - manual construction
539        let mut header = Vec::new();
540        let flags: u16 = 0x0001; // Version 1
541        header.extend_from_slice(&flags.to_be_bytes());
542        header.extend_from_slice(&0x880Bu16.to_be_bytes()); // PPP protocol
543
544        let result = parser.parse(&header, &context);
545
546        assert!(result.is_ok());
547        assert_eq!(
548            result.get("version"),
549            Some(&FieldValue::UInt8(gre_version::PPTP_ENHANCED))
550        );
551        assert_eq!(result.get("version_valid"), Some(&FieldValue::Bool(true)));
552        assert_eq!(
553            result.get("version_name"),
554            Some(&FieldValue::Str("PPTP-Enhanced"))
555        );
556    }
557
558    // Test 13: Invalid version (version 2-7)
559    #[test]
560    fn test_invalid_version() {
561        let parser = GreProtocol;
562        let mut context = ParseContext::new(1);
563        context.insert_hint("ip_protocol", 47);
564
565        // Test versions 2-7 (all invalid)
566        for version in 2..=7u16 {
567            let mut header = Vec::new();
568            let flags: u16 = version; // Version in bits 0-2
569            header.extend_from_slice(&flags.to_be_bytes());
570            header.extend_from_slice(&ethertype::IPV4.to_be_bytes());
571
572            let result = parser.parse(&header, &context);
573
574            assert!(result.is_ok()); // Still parses (lenient)
575            assert_eq!(
576                result.get("version"),
577                Some(&FieldValue::UInt8(version as u8))
578            );
579            assert_eq!(result.get("version_valid"), Some(&FieldValue::Bool(false)));
580            assert_eq!(
581                result.get("version_name"),
582                Some(&FieldValue::Str("Unknown"))
583            );
584        }
585    }
586
587    // Test 14: Checksum verification - valid checksum
588    #[test]
589    fn test_checksum_valid() {
590        let parser = GreProtocol;
591        let mut context = ParseContext::new(1);
592        context.insert_hint("ip_protocol", 47);
593
594        // Create GRE header with checksum flag
595        let mut packet = Vec::new();
596        let flags: u16 = 0x8000; // Checksum present
597        packet.extend_from_slice(&flags.to_be_bytes());
598        packet.extend_from_slice(&ethertype::IPV4.to_be_bytes()); // IPv4
599
600        // Placeholder for checksum and reserved (will be filled)
601        packet.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // checksum + reserved
602
603        // Add some payload
604        packet.extend_from_slice(&[0x45, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00]);
605
606        // Calculate checksum (set checksum field to 0 first)
607        let checksum = internet_checksum(&packet);
608
609        // Insert correct checksum
610        packet[4] = (checksum >> 8) as u8;
611        packet[5] = (checksum & 0xFF) as u8;
612
613        let result = parser.parse(&packet, &context);
614
615        assert!(result.is_ok());
616        assert_eq!(
617            result.get("checksum_present"),
618            Some(&FieldValue::Bool(true))
619        );
620        assert_eq!(result.get("checksum_valid"), Some(&FieldValue::Bool(true)));
621    }
622
623    // Test 15: Checksum verification - invalid checksum
624    #[test]
625    fn test_checksum_invalid() {
626        let parser = GreProtocol;
627        let mut context = ParseContext::new(1);
628        context.insert_hint("ip_protocol", 47);
629
630        // Create GRE header with wrong checksum
631        let mut packet = Vec::new();
632        let flags: u16 = 0x8000; // Checksum present
633        packet.extend_from_slice(&flags.to_be_bytes());
634        packet.extend_from_slice(&ethertype::IPV4.to_be_bytes());
635
636        // Wrong checksum (0xABCD instead of correct value)
637        packet.extend_from_slice(&[0xAB, 0xCD, 0x00, 0x00]);
638
639        // Add payload
640        packet.extend_from_slice(&[0x45, 0x00, 0x00, 0x28]);
641
642        let result = parser.parse(&packet, &context);
643
644        assert!(result.is_ok()); // Still parses (lenient)
645        assert_eq!(
646            result.get("checksum_present"),
647            Some(&FieldValue::Bool(true))
648        );
649        assert_eq!(result.get("checksum_valid"), Some(&FieldValue::Bool(false)));
650    }
651
652    // Test 16: Header length calculation
653    #[test]
654    fn test_header_length() {
655        let parser = GreProtocol;
656        let mut context = ParseContext::new(1);
657        context.insert_hint("ip_protocol", 47);
658
659        // Minimal header (4 bytes)
660        let header_min = create_gre_header(false, false, false, ethertype::IPV4);
661        let result = parser.parse(&header_min, &context);
662        assert!(result.is_ok());
663        assert_eq!(result.get("header_length"), Some(&FieldValue::UInt8(4)));
664
665        // With checksum (4 + 4 = 8 bytes)
666        let mut header_chk = create_gre_header(true, false, false, ethertype::IPV4);
667        header_chk.extend_from_slice(&[0x00; 4]); // checksum + reserved
668        let result = parser.parse(&header_chk, &context);
669        assert!(result.is_ok());
670        assert_eq!(result.get("header_length"), Some(&FieldValue::UInt8(8)));
671
672        // With key (4 + 4 = 8 bytes)
673        let mut header_key = create_gre_header(false, true, false, ethertype::IPV4);
674        header_key.extend_from_slice(&[0x00; 4]); // key
675        let result = parser.parse(&header_key, &context);
676        assert!(result.is_ok());
677        assert_eq!(result.get("header_length"), Some(&FieldValue::UInt8(8)));
678
679        // With sequence (4 + 4 = 8 bytes)
680        let mut header_seq = create_gre_header(false, false, true, ethertype::IPV4);
681        header_seq.extend_from_slice(&[0x00; 4]); // sequence
682        let result = parser.parse(&header_seq, &context);
683        assert!(result.is_ok());
684        assert_eq!(result.get("header_length"), Some(&FieldValue::UInt8(8)));
685
686        // All optional fields (4 + 4 + 4 + 4 = 16 bytes)
687        let mut header_all = create_gre_header(true, true, true, ethertype::IPV4);
688        header_all.extend_from_slice(&[0x00; 4]); // checksum + reserved
689        header_all.extend_from_slice(&[0x00; 4]); // key
690        header_all.extend_from_slice(&[0x00; 4]); // sequence
691        let result = parser.parse(&header_all, &context);
692        assert!(result.is_ok());
693        assert_eq!(result.get("header_length"), Some(&FieldValue::UInt8(16)));
694    }
695
696    // Test 17: Schema fields include new version and checksum validation fields
697    #[test]
698    fn test_schema_fields_complete() {
699        let parser = GreProtocol;
700        let fields = parser.schema_fields();
701
702        let field_names: Vec<&str> = fields.iter().map(|f| f.name).collect();
703        assert!(field_names.contains(&"gre.checksum_present"));
704        assert!(field_names.contains(&"gre.key_present"));
705        assert!(field_names.contains(&"gre.sequence_present"));
706        assert!(field_names.contains(&"gre.version"));
707        assert!(field_names.contains(&"gre.version_valid"));
708        assert!(field_names.contains(&"gre.version_name"));
709        assert!(field_names.contains(&"gre.protocol"));
710        assert!(field_names.contains(&"gre.checksum"));
711        assert!(field_names.contains(&"gre.checksum_valid"));
712        assert!(field_names.contains(&"gre.key"));
713        assert!(field_names.contains(&"gre.sequence"));
714        assert!(field_names.contains(&"gre.header_length"));
715    }
716
717    // Test 18: internet_checksum function directly
718    #[test]
719    fn test_internet_checksum_function() {
720        // Test with known data
721        // Simple test: checksum of all zeros should be 0xFFFF
722        let zeros = [0u8; 10];
723        assert_eq!(internet_checksum(&zeros), 0xFFFF);
724
725        // Test with 0xFFFF (ones complement of 0)
726        let ffff = [0xFF, 0xFF];
727        assert_eq!(internet_checksum(&ffff), 0x0000);
728
729        // Test odd length data
730        let odd = [0x01, 0x02, 0x03];
731        let _cksum = internet_checksum(&odd);
732        // Just verify it doesn't panic
733
734        // Test checksum verification: original data + checksum should give 0
735        let mut test_data = vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
736        let initial_sum = internet_checksum(&test_data);
737        // Add the checksum to the data
738        test_data.push((initial_sum >> 8) as u8);
739        test_data.push((initial_sum & 0xFF) as u8);
740        // Now checksum should be 0
741        assert_eq!(internet_checksum(&test_data), 0);
742    }
743
744    // Test 19: Missing checksum field when flag set
745    #[test]
746    fn test_gre_missing_checksum_field() {
747        let parser = GreProtocol;
748        let mut context = ParseContext::new(1);
749        context.insert_hint("ip_protocol", 47);
750
751        // Checksum flag set but no checksum data
752        let header = create_gre_header(true, false, false, ethertype::IPV4);
753
754        let result = parser.parse(&header, &context);
755        assert!(!result.is_ok());
756        assert!(result.error.unwrap().contains("missing checksum field"));
757    }
758
759    // Test 20: Missing sequence field when flag set
760    #[test]
761    fn test_gre_missing_sequence_field() {
762        let parser = GreProtocol;
763        let mut context = ParseContext::new(1);
764        context.insert_hint("ip_protocol", 47);
765
766        // Sequence flag set but no sequence data
767        let header = create_gre_header(false, false, true, ethertype::IPV4);
768
769        let result = parser.parse(&header, &context);
770        assert!(!result.is_ok());
771        assert!(result.error.unwrap().contains("missing sequence field"));
772    }
773}