packet_strata/packet/tunnel/
pptp.rs1use 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
89pub const PPTP_PROTOCOL_PPP: u16 = 0x880B;
91
92#[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 pub const FLAG_CHECKSUM: u16 = 0x8000; pub const FLAG_ROUTING: u16 = 0x4000; pub const FLAG_KEY: u16 = 0x2000; pub const FLAG_SEQUENCE: u16 = 0x1000; pub const FLAG_STRICT_ROUTE: u16 = 0x0800; pub const FLAG_ACK: u16 = 0x0080; pub const VERSION_MASK: u16 = 0x0007; pub const RECUR_MASK: u16 = 0x0700; pub const FLAGS_MASK: u16 = 0x0078; pub const VERSION_PPTP: u16 = 0x0001; #[allow(unused)]
134 const NAME: &'static str = "PptpGreHeader";
135
136 #[inline]
138 pub fn flags_version(&self) -> u16 {
139 self.flags_version.get()
140 }
141
142 #[inline]
144 pub fn version(&self) -> u8 {
145 (self.flags_version() & Self::VERSION_MASK) as u8
146 }
147
148 #[inline]
150 pub fn protocol_type(&self) -> EtherProto {
151 self.protocol_type.get().into()
152 }
153
154 #[inline]
156 pub fn payload_length(&self) -> u16 {
157 self.payload_length.get()
158 }
159
160 #[inline]
162 pub fn call_id(&self) -> u16 {
163 self.call_id.get()
164 }
165
166 #[inline]
168 pub fn has_checksum(&self) -> bool {
169 self.flags_version() & Self::FLAG_CHECKSUM != 0
170 }
171
172 #[inline]
174 pub fn has_routing(&self) -> bool {
175 self.flags_version() & Self::FLAG_ROUTING != 0
176 }
177
178 #[inline]
180 pub fn has_key(&self) -> bool {
181 self.flags_version() & Self::FLAG_KEY != 0
182 }
183
184 #[inline]
186 pub fn has_sequence(&self) -> bool {
187 self.flags_version() & Self::FLAG_SEQUENCE != 0
188 }
189
190 #[inline]
192 pub fn has_strict_route(&self) -> bool {
193 self.flags_version() & Self::FLAG_STRICT_ROUTE != 0
194 }
195
196 #[inline]
198 pub fn has_ack(&self) -> bool {
199 self.flags_version() & Self::FLAG_ACK != 0
200 }
201
202 #[inline]
204 pub fn recursion_control(&self) -> u8 {
205 ((self.flags_version() & Self::RECUR_MASK) >> 8) as u8
206 }
207
208 #[inline]
210 fn is_valid(&self) -> bool {
211 if self.version() != 1 {
213 return false;
214 }
215
216 if !self.has_key() {
218 return false;
219 }
220
221 if self.has_checksum() {
223 return false;
224 }
225
226 if self.has_routing() {
228 return false;
229 }
230
231 if self.has_strict_route() {
233 return false;
234 }
235
236 if self.recursion_control() != 0 {
238 return false;
239 }
240
241 let reserved = self.flags_version() & Self::FLAGS_MASK;
243 if reserved != 0 {
244 return false;
245 }
246
247 true
248 }
249
250 #[inline]
252 pub fn header_length(&self) -> usize {
253 let mut len = Self::FIXED_LEN; if self.has_sequence() {
257 len += 4;
258 }
259
260 if self.has_ack() {
262 len += 4;
263 }
264
265 len
266 }
267
268 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#[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 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 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 #[inline]
371 fn total_len(&self, _buf: &[u8]) -> usize {
372 self.header_length()
373 }
374
375 #[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), 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), 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); }
479
480 #[test]
481 fn test_pptp_gre_with_ack() {
482 let header = PptpGreHeader {
483 flags_version: U16::new(0x2081), 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); }
495
496 #[test]
497 fn test_pptp_gre_with_sequence_and_ack() {
498 let header = PptpGreHeader {
499 flags_version: U16::new(0x3081), 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); }
511
512 #[test]
513 fn test_pptp_gre_version_validation() {
514 let header_v0 = PptpGreHeader {
516 flags_version: U16::new(0x2000), 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 let header_v2 = PptpGreHeader {
525 flags_version: U16::new(0x2002), 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 let header = PptpGreHeader {
537 flags_version: U16::new(0x0001), 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 let header = PptpGreHeader {
549 flags_version: U16::new(0xA001), 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 let header = PptpGreHeader {
561 flags_version: U16::new(0x6001), 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 packet.extend_from_slice(&0x2001u16.to_be_bytes()); packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); packet.extend_from_slice(&0x0007u16.to_be_bytes()); packet.extend_from_slice(&0x002Au16.to_be_bytes()); 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 packet.extend_from_slice(&0x3001u16.to_be_bytes()); packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); packet.extend_from_slice(&0x0004u16.to_be_bytes()); packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.extend_from_slice(&0x12345678u32.to_be_bytes()); 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 packet.extend_from_slice(&0x2081u16.to_be_bytes()); packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.extend_from_slice(&0x00000005u32.to_be_bytes()); 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 packet.extend_from_slice(&0x3081u16.to_be_bytes()); packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes()); packet.extend_from_slice(&0x0008u16.to_be_bytes()); packet.extend_from_slice(&0x0064u16.to_be_bytes()); packet.extend_from_slice(&0x00000010u32.to_be_bytes()); packet.extend_from_slice(&0x0000000Fu32.to_be_bytes()); 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]; 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 packet.extend_from_slice(&0x2000u16.to_be_bytes()); 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), 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), 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), 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 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 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 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 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 let mut packet = Vec::new();
768
769 packet.extend_from_slice(&0x2081u16.to_be_bytes()); packet.extend_from_slice(&PPTP_PROTOCOL_PPP.to_be_bytes());
771 packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.extend_from_slice(&0x00000042u32.to_be_bytes()); 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}