Skip to main content

packet_strata/packet/tunnel/
pptp.rs

1//! PPTP GRE (Enhanced GRE version 1) protocol parser
2//!
3//! This module implements parsing for Enhanced GRE as defined in RFC 2637
4//! (Point-to-Point Tunneling Protocol). Enhanced GRE is version 1 of GRE
5//! with specific extensions for PPTP tunneling.
6//!
7//! # PPTP GRE Header Format
8//!
9//! ```text
10//!  0                   1                   2                   3
11//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13//! |C|R|K|S|s|Recur|A| Flags | Ver |         Protocol Type         |
14//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15//! |    Key (Payload Length)       |       Key (Call ID)           |
16//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17//! |                  Sequence Number (Optional)                   |
18//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19//! |               Acknowledgment Number (Optional)                |
20//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21//! ```
22//!
23//! # Differences from standard GRE
24//!
25//! - Version field MUST be 1
26//! - Key flag (K) MUST be set
27//! - Protocol type is typically 0x880B (PPP)
28//! - Key field is split into Payload Length (16 bits) and Call ID (16 bits)
29//! - Acknowledgment number support (A flag)
30//! - Checksum and Routing fields MUST NOT be present
31//!
32//! # Examples
33//!
34//! ## PPTP GRE with sequence number
35//!
36//! ```
37//! use packet_strata::packet::tunnel::pptp::PptpGreHeader;
38//! use packet_strata::packet::HeaderParser;
39//!
40//! // PPTP GRE packet with sequence number
41//! let packet = vec![
42//!     0x30, 0x01,  // flags_version (K + S, version 1)
43//!     0x88, 0x0B,  // protocol_type (PPP)
44//!     0x00, 0x10,  // payload_length = 16
45//!     0x00, 0x2A,  // call_id = 42
46//!     0x00, 0x00, 0x00, 0x01,  // sequence_number = 1
47//!     // ... PPP payload follows ...
48//! ];
49//!
50//! let (header, payload) = PptpGreHeader::from_bytes(&packet).unwrap();
51//! assert_eq!(header.version(), 1);
52//! assert_eq!(header.call_id(), 42);
53//! assert_eq!(header.payload_length(), 16);
54//! assert_eq!(header.sequence_number().unwrap(), 1);
55//! ```
56//!
57//! ## PPTP GRE with acknowledgment
58//!
59//! ```
60//! use packet_strata::packet::tunnel::pptp::PptpGreHeader;
61//! use packet_strata::packet::HeaderParser;
62//!
63//! // PPTP GRE packet with sequence and acknowledgment
64//! let packet = vec![
65//!     0x30, 0x81,  // flags_version (K + S + A, version 1)
66//!     0x88, 0x0B,  // protocol_type (PPP)
67//!     0x00, 0x08,  // payload_length = 8
68//!     0x00, 0x01,  // call_id = 1
69//!     0x00, 0x00, 0x00, 0x05,  // sequence_number = 5
70//!     0x00, 0x00, 0x00, 0x04,  // acknowledgment_number = 4
71//!     // ... PPP payload follows ...
72//! ];
73//!
74//! let (header, _) = PptpGreHeader::from_bytes(&packet).unwrap();
75//! assert!(header.has_sequence());
76//! assert!(header.has_ack());
77//! assert_eq!(header.sequence_number().unwrap(), 5);
78//! assert_eq!(header.acknowledgment_number().unwrap(), 4);
79//! ```
80
81use std::fmt::{self, Formatter};
82
83use zerocopy::byteorder::{BigEndian, U16};
84use zerocopy::{FromBytes, IntoBytes, Unaligned};
85
86use crate::packet::protocol::EtherProto;
87use crate::packet::{HeaderParser, PacketHeader};
88
89/// PPTP GRE Protocol Type (PPP)
90pub const PPTP_PROTOCOL_PPP: u16 = 0x880B;
91
92/// PPTP GRE Header structure as defined in RFC 2637
93///
94/// This is the fixed portion of the Enhanced GRE header used by PPTP.
95/// The header always includes the Key field (split into Payload Length and Call ID).
96///
97/// Minimum header format (8 bytes):
98/// ```text
99///  0                   1                   2                   3
100///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
101/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102/// |C|R|K|S|s|Recur|A| Flags | Ver |         Protocol Type         |
103/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104/// |         Payload Length        |           Call ID             |
105/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106/// ```
107#[repr(C, packed)]
108#[derive(
109    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
110)]
111pub struct PptpGreHeader {
112    flags_version: U16<BigEndian>,
113    protocol_type: U16<BigEndian>,
114    payload_length: U16<BigEndian>,
115    call_id: U16<BigEndian>,
116}
117
118impl PptpGreHeader {
119    // GRE Flags (in the high byte of flags_version)
120    pub const FLAG_CHECKSUM: u16 = 0x8000; // Checksum Present (C bit) - MUST be 0 for PPTP
121    pub const FLAG_ROUTING: u16 = 0x4000; // Routing Present (R bit) - MUST be 0 for PPTP
122    pub const FLAG_KEY: u16 = 0x2000; // Key Present (K bit) - MUST be 1 for PPTP
123    pub const FLAG_SEQUENCE: u16 = 0x1000; // Sequence Number Present (S bit)
124    pub const FLAG_STRICT_ROUTE: u16 = 0x0800; // Strict Source Route (s bit) - MUST be 0
125    pub const FLAG_ACK: u16 = 0x0080; // Acknowledgment Present (A bit)
126
127    pub const VERSION_MASK: u16 = 0x0007; // Version field (bits 13-15)
128    pub const RECUR_MASK: u16 = 0x0700; // Recursion control (bits 5-7) - MUST be 0
129    pub const FLAGS_MASK: u16 = 0x0078; // Reserved flags (bits 8-11) - MUST be 0
130
131    pub const VERSION_PPTP: u16 = 0x0001; // Enhanced GRE version (RFC 2637 - PPTP)
132
133    #[allow(unused)]
134    const NAME: &'static str = "PptpGreHeader";
135
136    /// Returns the flags and version field
137    #[inline]
138    pub fn flags_version(&self) -> u16 {
139        self.flags_version.get()
140    }
141
142    /// Returns the GRE version number (should be 1 for PPTP)
143    #[inline]
144    pub fn version(&self) -> u8 {
145        (self.flags_version() & Self::VERSION_MASK) as u8
146    }
147
148    /// Returns the protocol type field (typically 0x880B for PPP)
149    #[inline]
150    pub fn protocol_type(&self) -> EtherProto {
151        self.protocol_type.get().into()
152    }
153
154    /// Returns the payload length (size of the PPP payload, not including GRE header)
155    #[inline]
156    pub fn payload_length(&self) -> u16 {
157        self.payload_length.get()
158    }
159
160    /// Returns the Call ID used to identify the PPTP session
161    #[inline]
162    pub fn call_id(&self) -> u16 {
163        self.call_id.get()
164    }
165
166    /// Check if Checksum Present flag is set (should be 0 for PPTP)
167    #[inline]
168    pub fn has_checksum(&self) -> bool {
169        self.flags_version() & Self::FLAG_CHECKSUM != 0
170    }
171
172    /// Check if Routing Present flag is set (should be 0 for PPTP)
173    #[inline]
174    pub fn has_routing(&self) -> bool {
175        self.flags_version() & Self::FLAG_ROUTING != 0
176    }
177
178    /// Check if Key Present flag is set (should always be 1 for PPTP)
179    #[inline]
180    pub fn has_key(&self) -> bool {
181        self.flags_version() & Self::FLAG_KEY != 0
182    }
183
184    /// Check if Sequence Number Present flag is set
185    #[inline]
186    pub fn has_sequence(&self) -> bool {
187        self.flags_version() & Self::FLAG_SEQUENCE != 0
188    }
189
190    /// Check if Strict Source Route flag is set (should be 0 for PPTP)
191    #[inline]
192    pub fn has_strict_route(&self) -> bool {
193        self.flags_version() & Self::FLAG_STRICT_ROUTE != 0
194    }
195
196    /// Check if Acknowledgment flag is set
197    #[inline]
198    pub fn has_ack(&self) -> bool {
199        self.flags_version() & Self::FLAG_ACK != 0
200    }
201
202    /// Returns the recursion control value (should be 0 for PPTP)
203    #[inline]
204    pub fn recursion_control(&self) -> u8 {
205        ((self.flags_version() & Self::RECUR_MASK) >> 8) as u8
206    }
207
208    /// Validates the PPTP GRE header according to RFC 2637
209    #[inline]
210    fn is_valid(&self) -> bool {
211        // Version MUST be 1
212        if self.version() != 1 {
213            return false;
214        }
215
216        // Key flag MUST be set
217        if !self.has_key() {
218            return false;
219        }
220
221        // Checksum flag MUST NOT be set
222        if self.has_checksum() {
223            return false;
224        }
225
226        // Routing flag MUST NOT be set
227        if self.has_routing() {
228            return false;
229        }
230
231        // Strict Source Route flag MUST NOT be set
232        if self.has_strict_route() {
233            return false;
234        }
235
236        // Recursion control MUST be 0
237        if self.recursion_control() != 0 {
238            return false;
239        }
240
241        // Reserved flags MUST be 0
242        let reserved = self.flags_version() & Self::FLAGS_MASK;
243        if reserved != 0 {
244            return false;
245        }
246
247        true
248    }
249
250    /// Calculate the total header length including optional fields
251    #[inline]
252    pub fn header_length(&self) -> usize {
253        let mut len = Self::FIXED_LEN; // 8 bytes for PPTP GRE fixed header
254
255        // Add 4 bytes for sequence number (if present)
256        if self.has_sequence() {
257            len += 4;
258        }
259
260        // Add 4 bytes for acknowledgment number (if present)
261        if self.has_ack() {
262            len += 4;
263        }
264
265        len
266    }
267
268    /// Returns a string representation of active flags
269    pub fn flags_string(&self) -> String {
270        let mut flags = Vec::new();
271
272        if self.has_checksum() {
273            flags.push("C");
274        }
275        if self.has_routing() {
276            flags.push("R");
277        }
278        if self.has_key() {
279            flags.push("K");
280        }
281        if self.has_sequence() {
282            flags.push("S");
283        }
284        if self.has_strict_route() {
285            flags.push("s");
286        }
287        if self.has_ack() {
288            flags.push("A");
289        }
290
291        if flags.is_empty() {
292            "none".to_string()
293        } else {
294            flags.join("")
295        }
296    }
297}
298
299/// PPTP GRE Header with optional fields parsed
300#[derive(Debug, Clone)]
301pub struct PptpGreHeaderOpt<'a> {
302    pub header: &'a PptpGreHeader,
303    pub raw_options: &'a [u8],
304}
305
306impl<'a> PptpGreHeaderOpt<'a> {
307    /// Get the sequence number if present
308    pub fn sequence_number(&self) -> Option<u32> {
309        if !self.header.has_sequence() {
310            return None;
311        }
312
313        if self.raw_options.len() < 4 {
314            return None;
315        }
316
317        let seq_bytes = &self.raw_options[0..4];
318        Some(u32::from_be_bytes([
319            seq_bytes[0],
320            seq_bytes[1],
321            seq_bytes[2],
322            seq_bytes[3],
323        ]))
324    }
325
326    /// Get the acknowledgment number if present
327    pub fn acknowledgment_number(&self) -> Option<u32> {
328        if !self.header.has_ack() {
329            return None;
330        }
331
332        let mut offset = 0;
333        if self.header.has_sequence() {
334            offset += 4;
335        }
336
337        if self.raw_options.len() < offset + 4 {
338            return None;
339        }
340
341        let ack_bytes = &self.raw_options[offset..offset + 4];
342        Some(u32::from_be_bytes([
343            ack_bytes[0],
344            ack_bytes[1],
345            ack_bytes[2],
346            ack_bytes[3],
347        ]))
348    }
349}
350
351impl std::ops::Deref for PptpGreHeaderOpt<'_> {
352    type Target = PptpGreHeader;
353
354    #[inline]
355    fn deref(&self) -> &Self::Target {
356        self.header
357    }
358}
359
360impl PacketHeader for PptpGreHeader {
361    const NAME: &'static str = "PptpGreHeader";
362    type InnerType = EtherProto;
363
364    #[inline]
365    fn inner_type(&self) -> Self::InnerType {
366        self.protocol_type()
367    }
368
369    /// Returns the total header length in bytes (including optional fields)
370    #[inline]
371    fn total_len(&self, _buf: &[u8]) -> usize {
372        self.header_length()
373    }
374
375    /// Validates the PPTP GRE header
376    #[inline]
377    fn is_valid(&self) -> bool {
378        self.is_valid()
379    }
380}
381
382impl HeaderParser for PptpGreHeader {
383    type Output<'a> = PptpGreHeaderOpt<'a>;
384
385    #[inline]
386    fn into_view<'a>(header: &'a Self, raw_options: &'a [u8]) -> Self::Output<'a> {
387        PptpGreHeaderOpt {
388            header,
389            raw_options,
390        }
391    }
392}
393
394impl fmt::Display for PptpGreHeader {
395    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
396        write!(
397            f,
398            "PPTP-GRE v{} proto={}(0x{:04x}) call_id={} payload_len={} flags={}",
399            self.version(),
400            self.protocol_type(),
401            self.protocol_type().0,
402            self.call_id(),
403            self.payload_length(),
404            self.flags_string()
405        )
406    }
407}
408
409impl fmt::Display for PptpGreHeaderOpt<'_> {
410    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
411        write!(
412            f,
413            "PPTP-GRE v{} proto={} call_id={} payload_len={} flags={}",
414            self.version(),
415            self.protocol_type(),
416            self.call_id(),
417            self.payload_length(),
418            self.flags_string()
419        )?;
420
421        if let Some(seq) = self.sequence_number() {
422            write!(f, " seq={}", seq)?;
423        }
424
425        if let Some(ack) = self.acknowledgment_number() {
426            write!(f, " ack={}", ack)?;
427        }
428
429        Ok(())
430    }
431}
432
433#[cfg(test)]
434mod tests {
435    use super::*;
436
437    #[test]
438    fn test_pptp_gre_header_size() {
439        assert_eq!(std::mem::size_of::<PptpGreHeader>(), 8);
440        assert_eq!(PptpGreHeader::FIXED_LEN, 8);
441    }
442
443    #[test]
444    fn test_pptp_gre_basic_header() {
445        let header = PptpGreHeader {
446            flags_version: U16::new(0x2001), // Key present, version 1
447            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
448            payload_length: U16::new(100),
449            call_id: U16::new(42),
450        };
451
452        assert_eq!(header.version(), 1);
453        assert_eq!(header.protocol_type().0.get(), PPTP_PROTOCOL_PPP);
454        assert!(header.has_key());
455        assert!(!header.has_checksum());
456        assert!(!header.has_sequence());
457        assert!(!header.has_ack());
458        assert!(header.is_valid());
459        assert_eq!(header.header_length(), 8);
460        assert_eq!(header.payload_length(), 100);
461        assert_eq!(header.call_id(), 42);
462    }
463
464    #[test]
465    fn test_pptp_gre_with_sequence() {
466        let header = PptpGreHeader {
467            flags_version: U16::new(0x3001), // Key + Sequence, version 1
468            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
469            payload_length: U16::new(50),
470            call_id: U16::new(1),
471        };
472
473        assert!(header.has_key());
474        assert!(header.has_sequence());
475        assert!(!header.has_ack());
476        assert!(header.is_valid());
477        assert_eq!(header.header_length(), 12); // 8 + 4 for sequence
478    }
479
480    #[test]
481    fn test_pptp_gre_with_ack() {
482        let header = PptpGreHeader {
483            flags_version: U16::new(0x2081), // Key + Ack, version 1
484            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
485            payload_length: U16::new(0),
486            call_id: U16::new(1),
487        };
488
489        assert!(header.has_key());
490        assert!(!header.has_sequence());
491        assert!(header.has_ack());
492        assert!(header.is_valid());
493        assert_eq!(header.header_length(), 12); // 8 + 4 for ack
494    }
495
496    #[test]
497    fn test_pptp_gre_with_sequence_and_ack() {
498        let header = PptpGreHeader {
499            flags_version: U16::new(0x3081), // Key + Sequence + Ack, version 1
500            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
501            payload_length: U16::new(64),
502            call_id: U16::new(100),
503        };
504
505        assert!(header.has_key());
506        assert!(header.has_sequence());
507        assert!(header.has_ack());
508        assert!(header.is_valid());
509        assert_eq!(header.header_length(), 16); // 8 + 4 + 4
510    }
511
512    #[test]
513    fn test_pptp_gre_version_validation() {
514        // Invalid: version 0
515        let header_v0 = PptpGreHeader {
516            flags_version: U16::new(0x2000), // Key present, but version 0
517            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
518            payload_length: U16::new(0),
519            call_id: U16::new(1),
520        };
521        assert!(!header_v0.is_valid());
522
523        // Invalid: version 2
524        let header_v2 = PptpGreHeader {
525            flags_version: U16::new(0x2002), // Key present, but version 2
526            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
527            payload_length: U16::new(0),
528            call_id: U16::new(1),
529        };
530        assert!(!header_v2.is_valid());
531    }
532
533    #[test]
534    fn test_pptp_gre_key_flag_required() {
535        // Invalid: Key flag not set
536        let header = PptpGreHeader {
537            flags_version: U16::new(0x0001), // version 1, but no key
538            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
539            payload_length: U16::new(0),
540            call_id: U16::new(1),
541        };
542        assert!(!header.is_valid());
543    }
544
545    #[test]
546    fn test_pptp_gre_checksum_forbidden() {
547        // Invalid: Checksum flag set
548        let header = PptpGreHeader {
549            flags_version: U16::new(0xA001), // Key + Checksum, version 1
550            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
551            payload_length: U16::new(0),
552            call_id: U16::new(1),
553        };
554        assert!(!header.is_valid());
555    }
556
557    #[test]
558    fn test_pptp_gre_routing_forbidden() {
559        // Invalid: Routing flag set
560        let header = PptpGreHeader {
561            flags_version: U16::new(0x6001), // Key + Routing, version 1
562            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
563            payload_length: U16::new(0),
564            call_id: U16::new(1),
565        };
566        assert!(!header.is_valid());
567    }
568
569    #[test]
570    fn test_pptp_gre_parsing_basic() {
571        let mut packet = Vec::new();
572
573        // PPTP GRE header: Key present, version 1
574        packet.extend_from_slice(&0x2001u16.to_be_bytes()); // flags_version
575        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); // protocol_type
576        packet.extend_from_slice(&0x0007u16.to_be_bytes()); // payload_length
577        packet.extend_from_slice(&0x002Au16.to_be_bytes()); // call_id = 42
578
579        // Add some payload
580        packet.extend_from_slice(b"payload");
581
582        let result = PptpGreHeader::from_bytes(&packet);
583        assert!(result.is_ok());
584
585        let (header, payload) = result.unwrap();
586        assert_eq!(header.version(), 1);
587        assert_eq!(header.call_id(), 42);
588        assert_eq!(header.payload_length(), 7);
589        assert_eq!(payload, b"payload");
590    }
591
592    #[test]
593    fn test_pptp_gre_parsing_with_sequence() {
594        let mut packet = Vec::new();
595
596        // PPTP GRE header with sequence
597        packet.extend_from_slice(&0x3001u16.to_be_bytes()); // flags_version (K + S, v1)
598        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); // protocol_type
599        packet.extend_from_slice(&0x0004u16.to_be_bytes()); // payload_length
600        packet.extend_from_slice(&0x0001u16.to_be_bytes()); // call_id
601        packet.extend_from_slice(&0x12345678u32.to_be_bytes()); // sequence_number
602
603        // Add payload
604        packet.extend_from_slice(b"test");
605
606        let result = PptpGreHeader::from_bytes(&packet);
607        assert!(result.is_ok());
608
609        let (header, payload) = result.unwrap();
610        assert!(header.has_sequence());
611        assert_eq!(header.sequence_number().unwrap(), 0x12345678);
612        assert_eq!(payload, b"test");
613    }
614
615    #[test]
616    fn test_pptp_gre_parsing_with_ack() {
617        let mut packet = Vec::new();
618
619        // PPTP GRE header with ack
620        packet.extend_from_slice(&0x2081u16.to_be_bytes()); // flags_version (K + A, v1)
621        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); // protocol_type
622        packet.extend_from_slice(&0x0000u16.to_be_bytes()); // payload_length = 0 (ack-only packet)
623        packet.extend_from_slice(&0x0001u16.to_be_bytes()); // call_id
624        packet.extend_from_slice(&0x00000005u32.to_be_bytes()); // acknowledgment_number
625
626        let result = PptpGreHeader::from_bytes(&packet);
627        assert!(result.is_ok());
628
629        let (header, _) = result.unwrap();
630        assert!(header.has_ack());
631        assert!(!header.has_sequence());
632        assert_eq!(header.acknowledgment_number().unwrap(), 5);
633    }
634
635    #[test]
636    fn test_pptp_gre_parsing_with_sequence_and_ack() {
637        let mut packet = Vec::new();
638
639        // PPTP GRE header with sequence and ack
640        packet.extend_from_slice(&0x3081u16.to_be_bytes()); // flags_version (K + S + A, v1)
641        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); // protocol_type
642        packet.extend_from_slice(&0x0008u16.to_be_bytes()); // payload_length
643        packet.extend_from_slice(&0x0064u16.to_be_bytes()); // call_id = 100
644        packet.extend_from_slice(&0x00000010u32.to_be_bytes()); // sequence_number = 16
645        packet.extend_from_slice(&0x0000000Fu32.to_be_bytes()); // acknowledgment_number = 15
646
647        // Add payload
648        packet.extend_from_slice(&[0u8; 8]);
649
650        let result = PptpGreHeader::from_bytes(&packet);
651        assert!(result.is_ok());
652
653        let (header, _) = result.unwrap();
654        assert!(header.has_sequence());
655        assert!(header.has_ack());
656        assert_eq!(header.call_id(), 100);
657        assert_eq!(header.sequence_number().unwrap(), 16);
658        assert_eq!(header.acknowledgment_number().unwrap(), 15);
659    }
660
661    #[test]
662    fn test_pptp_gre_parsing_too_small() {
663        let packet = vec![0u8; 7]; // Only 7 bytes, need 8
664
665        let result = PptpGreHeader::from_bytes(&packet);
666        assert!(result.is_err());
667    }
668
669    #[test]
670    fn test_pptp_gre_parsing_invalid_version() {
671        let mut packet = Vec::new();
672
673        // Invalid: version 0
674        packet.extend_from_slice(&0x2000u16.to_be_bytes()); // flags_version (K, v0)
675        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes());
676        packet.extend_from_slice(&0x0000u16.to_be_bytes());
677        packet.extend_from_slice(&0x0001u16.to_be_bytes());
678
679        let result = PptpGreHeader::from_bytes(&packet);
680        assert!(result.is_err());
681    }
682
683    #[test]
684    fn test_pptp_gre_flags_string() {
685        let header1 = PptpGreHeader {
686            flags_version: U16::new(0x2001), // K only
687            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
688            payload_length: U16::new(0),
689            call_id: U16::new(1),
690        };
691        assert_eq!(header1.flags_string(), "K");
692
693        let header2 = PptpGreHeader {
694            flags_version: U16::new(0x3001), // K + S
695            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
696            payload_length: U16::new(0),
697            call_id: U16::new(1),
698        };
699        assert_eq!(header2.flags_string(), "KS");
700
701        let header3 = PptpGreHeader {
702            flags_version: U16::new(0x3081), // K + S + A
703            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
704            payload_length: U16::new(0),
705            call_id: U16::new(1),
706        };
707        assert_eq!(header3.flags_string(), "KSA");
708    }
709
710    #[test]
711    fn test_pptp_gre_header_length_calculation() {
712        // No optional fields (just K)
713        let h1 = PptpGreHeader {
714            flags_version: U16::new(0x2001),
715            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
716            payload_length: U16::new(0),
717            call_id: U16::new(1),
718        };
719        assert_eq!(h1.header_length(), 8);
720
721        // With sequence
722        let h2 = PptpGreHeader {
723            flags_version: U16::new(0x3001),
724            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
725            payload_length: U16::new(0),
726            call_id: U16::new(1),
727        };
728        assert_eq!(h2.header_length(), 12);
729
730        // With ack
731        let h3 = PptpGreHeader {
732            flags_version: U16::new(0x2081),
733            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
734            payload_length: U16::new(0),
735            call_id: U16::new(1),
736        };
737        assert_eq!(h3.header_length(), 12);
738
739        // With sequence and ack
740        let h4 = PptpGreHeader {
741            flags_version: U16::new(0x3081),
742            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
743            payload_length: U16::new(0),
744            call_id: U16::new(1),
745        };
746        assert_eq!(h4.header_length(), 16);
747    }
748
749    #[test]
750    fn test_pptp_gre_display() {
751        let header = PptpGreHeader {
752            flags_version: U16::new(0x3081),
753            protocol_type: U16::new(PPTP_PROTOCOL_PPP),
754            payload_length: U16::new(100),
755            call_id: U16::new(42),
756        };
757
758        let display = format!("{}", header);
759        assert!(display.contains("PPTP-GRE"));
760        assert!(display.contains("call_id=42"));
761        assert!(display.contains("payload_len=100"));
762    }
763
764    #[test]
765    fn test_pptp_gre_ack_only_packet() {
766        // ACK-only packets are common in PPTP for flow control
767        let mut packet = Vec::new();
768
769        packet.extend_from_slice(&0x2081u16.to_be_bytes()); // K + A, v1
770        packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes());
771        packet.extend_from_slice(&0x0000u16.to_be_bytes()); // payload_length = 0
772        packet.extend_from_slice(&0x0001u16.to_be_bytes()); // call_id
773        packet.extend_from_slice(&0x00000042u32.to_be_bytes()); // ack number
774
775        let result = PptpGreHeader::from_bytes(&packet);
776        assert!(result.is_ok());
777
778        let (header, payload) = result.unwrap();
779        assert_eq!(header.payload_length(), 0);
780        assert!(header.has_ack());
781        assert!(!header.has_sequence());
782        assert_eq!(header.acknowledgment_number().unwrap(), 0x42);
783        assert!(payload.is_empty());
784    }
785}