trippy_packet/
icmp_extension.rs

1pub mod extension_structure {
2    use crate::buffer::Buffer;
3    use crate::error::{Error, Result};
4    use crate::icmp_extension::extension_object::ExtensionObjectPacket;
5
6    /// Represents an ICMP `ExtensionsPacket` pseudo object.
7    ///
8    /// The internal representation is held in network byte order (big-endian) and all accessor
9    /// methods take and return data in host byte order, converting as necessary for the given
10    /// architecture.
11    pub struct ExtensionsPacket<'a> {
12        buf: Buffer<'a>,
13    }
14
15    impl<'a> ExtensionsPacket<'a> {
16        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
17            if packet.len() >= Self::minimum_packet_size() {
18                Ok(Self {
19                    buf: Buffer::Mutable(packet),
20                })
21            } else {
22                Err(Error::InsufficientPacketBuffer(
23                    String::from("ExtensionsPacket"),
24                    Self::minimum_packet_size(),
25                    packet.len(),
26                ))
27            }
28        }
29
30        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
31            if packet.len() >= Self::minimum_packet_size() {
32                Ok(Self {
33                    buf: Buffer::Immutable(packet),
34                })
35            } else {
36                Err(Error::InsufficientPacketBuffer(
37                    String::from("ExtensionsPacket"),
38                    Self::minimum_packet_size(),
39                    packet.len(),
40                ))
41            }
42        }
43
44        #[must_use]
45        pub const fn minimum_packet_size() -> usize {
46            4
47        }
48
49        #[must_use]
50        pub fn packet(&self) -> &[u8] {
51            self.buf.as_slice()
52        }
53
54        #[must_use]
55        pub fn header(&self) -> &[u8] {
56            &self.buf.as_slice()[..Self::minimum_packet_size()]
57        }
58
59        /// An iterator of Extension Objects contained within this `ExtensionsPacket`.
60        #[must_use]
61        pub const fn objects(&self) -> ExtensionObjectIter<'_> {
62            ExtensionObjectIter::new(&self.buf)
63        }
64    }
65
66    pub struct ExtensionObjectIter<'a> {
67        buf: &'a Buffer<'a>,
68        offset: usize,
69    }
70
71    impl<'a> ExtensionObjectIter<'a> {
72        #[must_use]
73        pub const fn new(buf: &'a Buffer<'_>) -> Self {
74            Self {
75                buf,
76                offset: ExtensionsPacket::minimum_packet_size(),
77            }
78        }
79    }
80
81    impl<'a> Iterator for ExtensionObjectIter<'a> {
82        type Item = &'a [u8];
83
84        fn next(&mut self) -> Option<Self::Item> {
85            let buf_slice = self.buf.as_slice();
86            if self.offset > buf_slice.len() {
87                None
88            } else {
89                let object_bytes = &buf_slice[self.offset..];
90                if let Ok(object) = ExtensionObjectPacket::new_view(object_bytes) {
91                    let length = usize::from(object.get_length());
92                    // If a malformed extension object has a length that is less than the minimum
93                    // size or extends beyond the end of available bytes, then we discard it.
94                    if length < ExtensionObjectPacket::minimum_packet_size()
95                        || length > object_bytes.len()
96                    {
97                        return None;
98                    }
99                    self.offset += length;
100                    Some(object_bytes)
101                } else {
102                    None
103                }
104            }
105        }
106    }
107
108    #[cfg(test)]
109    mod tests {
110        use super::*;
111        use crate::icmp_extension::extension_header::ExtensionHeaderPacket;
112        use crate::icmp_extension::extension_object::{
113            ClassNum, ClassSubType, ExtensionObjectPacket,
114        };
115
116        #[test]
117        fn test_header() {
118            let buf = [
119                0x20, 0x00, 0x99, 0x3a, 0x00, 0x08, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
120            ];
121            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
122            let header = ExtensionHeaderPacket::new_view(extensions.header()).unwrap();
123            assert_eq!(2, header.get_version());
124            assert_eq!(0x993A, header.get_checksum());
125        }
126
127        #[test]
128        fn test_object_iterator() {
129            let buf = [
130                0x20, 0x00, 0x99, 0x3a, 0x00, 0x08, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
131            ];
132            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
133            let mut object_iter = extensions.objects();
134            let object_bytes = object_iter.next().unwrap();
135            let object = ExtensionObjectPacket::new_view(object_bytes).unwrap();
136            assert_eq!(8, object.get_length());
137            assert_eq!(
138                ClassNum::MultiProtocolLabelSwitchingLabelStack,
139                object.get_class_num()
140            );
141            assert_eq!(ClassSubType(1), object.get_class_subtype());
142            assert_eq!([0x04, 0xbb, 0x41, 0x01], object.payload());
143            assert!(object_iter.next().is_none());
144        }
145
146        #[test]
147        fn test_object_iterator_zero_length() {
148            let buf = [
149                0x20, 0x00, 0x99, 0x3a, 0x00, 0x00, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
150            ];
151            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
152            let mut object_iter = extensions.objects();
153            assert!(object_iter.next().is_none());
154        }
155
156        #[test]
157        fn test_object_iterator_minimum_length() {
158            let buf = [
159                0x20, 0x00, 0x99, 0x3a, 0x00, 0x04, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
160            ];
161            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
162            let mut object_iter = extensions.objects();
163            let object_bytes = object_iter.next().unwrap();
164            let object = ExtensionObjectPacket::new_view(object_bytes).unwrap();
165            assert_eq!(4, object.get_length());
166            assert_eq!(0, object.payload().len());
167        }
168
169        #[test]
170        fn test_object_iterator_length_to_short() {
171            let buf = [
172                0x20, 0x00, 0x99, 0x3a, 0x00, 0x03, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
173            ];
174            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
175            let mut object_iter = extensions.objects();
176            assert!(object_iter.next().is_none());
177        }
178
179        #[test]
180        fn test_object_iterator_length_to_long() {
181            let buf = [
182                0x20, 0x00, 0x99, 0x3a, 0xa7, 0xdd, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
183            ];
184            let extensions = ExtensionsPacket::new_view(&buf).unwrap();
185            let mut object_iter = extensions.objects();
186            assert!(object_iter.next().is_none());
187        }
188    }
189}
190
191pub mod extension_header {
192    use crate::buffer::Buffer;
193    use crate::error::{Error, Result};
194    use std::fmt::{Debug, Formatter};
195
196    const VERSION_OFFSET: usize = 0;
197    const CHECKSUM_OFFSET: usize = 2;
198
199    /// Represents an ICMP `ExtensionHeaderPacket`.
200    ///
201    /// The internal representation is held in network byte order (big-endian) and all accessor
202    /// methods take and return data in host byte order, converting as necessary for the given
203    /// architecture.
204    pub struct ExtensionHeaderPacket<'a> {
205        buf: Buffer<'a>,
206    }
207
208    impl<'a> ExtensionHeaderPacket<'a> {
209        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
210            if packet.len() >= Self::minimum_packet_size() {
211                Ok(Self {
212                    buf: Buffer::Mutable(packet),
213                })
214            } else {
215                Err(Error::InsufficientPacketBuffer(
216                    String::from("ExtensionHeaderPacket"),
217                    Self::minimum_packet_size(),
218                    packet.len(),
219                ))
220            }
221        }
222
223        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
224            if packet.len() >= Self::minimum_packet_size() {
225                Ok(Self {
226                    buf: Buffer::Immutable(packet),
227                })
228            } else {
229                Err(Error::InsufficientPacketBuffer(
230                    String::from("ExtensionHeaderPacket"),
231                    Self::minimum_packet_size(),
232                    packet.len(),
233                ))
234            }
235        }
236
237        #[must_use]
238        pub const fn minimum_packet_size() -> usize {
239            4
240        }
241
242        #[must_use]
243        pub fn get_version(&self) -> u8 {
244            (self.buf.read(VERSION_OFFSET) & 0xf0) >> 4
245        }
246
247        #[must_use]
248        pub fn get_checksum(&self) -> u16 {
249            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
250        }
251
252        pub fn set_version(&mut self, val: u8) {
253            *self.buf.write(VERSION_OFFSET) =
254                (self.buf.read(VERSION_OFFSET) & 0xf) | ((val & 0xf) << 4);
255        }
256
257        pub fn set_checksum(&mut self, val: u16) {
258            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
259        }
260
261        #[must_use]
262        pub fn packet(&self) -> &[u8] {
263            self.buf.as_slice()
264        }
265    }
266
267    impl Debug for ExtensionHeaderPacket<'_> {
268        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
269            f.debug_struct("ExtensionHeader")
270                .field("version", &self.get_version())
271                .field("checksum", &self.get_checksum())
272                .finish()
273        }
274    }
275
276    #[cfg(test)]
277    mod tests {
278        use super::*;
279
280        #[test]
281        fn test_version() {
282            let mut buf = [0_u8; ExtensionHeaderPacket::minimum_packet_size()];
283            let mut extension = ExtensionHeaderPacket::new(&mut buf).unwrap();
284            extension.set_version(0);
285            assert_eq!(0, extension.get_version());
286            assert_eq!([0x00], extension.packet()[0..1]);
287            extension.set_version(2);
288            assert_eq!(2, extension.get_version());
289            assert_eq!([0x20], extension.packet()[0..1]);
290            extension.set_version(15);
291            assert_eq!(15, extension.get_version());
292            assert_eq!([0xF0], extension.packet()[0..1]);
293        }
294
295        #[test]
296        fn test_checksum() {
297            let mut buf = [0_u8; ExtensionHeaderPacket::minimum_packet_size()];
298            let mut extension = ExtensionHeaderPacket::new(&mut buf).unwrap();
299            extension.set_checksum(0);
300            assert_eq!(0, extension.get_checksum());
301            assert_eq!([0x00, 0x00], extension.packet()[2..=3]);
302            extension.set_checksum(1999);
303            assert_eq!(1999, extension.get_checksum());
304            assert_eq!([0x07, 0xCF], extension.packet()[2..=3]);
305            extension.set_checksum(39226);
306            assert_eq!(39226, extension.get_checksum());
307            assert_eq!([0x99, 0x3A], extension.packet()[2..=3]);
308            extension.set_checksum(u16::MAX);
309            assert_eq!(u16::MAX, extension.get_checksum());
310            assert_eq!([0xFF, 0xFF], extension.packet()[2..=3]);
311        }
312
313        #[test]
314        fn test_extension_header_view() {
315            let buf = [
316                0x20, 0x00, 0x99, 0x3a, 0x00, 0x08, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01,
317            ];
318            let extension = ExtensionHeaderPacket::new_view(&buf).unwrap();
319            assert_eq!(2, extension.get_version());
320            assert_eq!(0x993A, extension.get_checksum());
321        }
322    }
323}
324
325pub mod extension_object {
326    use crate::buffer::Buffer;
327    use crate::error::{Error, Result};
328    use crate::fmt_payload;
329    use std::fmt::{Debug, Formatter};
330
331    /// The ICMP Extension Object Class Num.
332    #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
333    pub enum ClassNum {
334        MultiProtocolLabelSwitchingLabelStack,
335        InterfaceInformationObject,
336        InterfaceIdentificationObject,
337        ExtendedInformation,
338        Other(u8),
339    }
340
341    impl ClassNum {
342        #[must_use]
343        pub const fn id(&self) -> u8 {
344            match self {
345                Self::MultiProtocolLabelSwitchingLabelStack => 1,
346                Self::InterfaceInformationObject => 2,
347                Self::InterfaceIdentificationObject => 3,
348                Self::ExtendedInformation => 4,
349                Self::Other(id) => *id,
350            }
351        }
352    }
353
354    impl From<u8> for ClassNum {
355        fn from(val: u8) -> Self {
356            match val {
357                1 => Self::MultiProtocolLabelSwitchingLabelStack,
358                2 => Self::InterfaceInformationObject,
359                3 => Self::InterfaceIdentificationObject,
360                4 => Self::ExtendedInformation,
361                id => Self::Other(id),
362            }
363        }
364    }
365
366    /// The ICMP Extension Object Class Sub-type.
367    #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
368    pub struct ClassSubType(pub u8);
369
370    impl From<u8> for ClassSubType {
371        fn from(val: u8) -> Self {
372            Self(val)
373        }
374    }
375
376    const LENGTH_OFFSET: usize = 0;
377    const CLASS_NUM_OFFSET: usize = 2;
378    const CLASS_SUBTYPE_OFFSET: usize = 3;
379
380    /// Represents an ICMP `ExtensionObjectPacket`.
381    ///
382    /// The internal representation is held in network byte order (big-endian) and all accessor
383    /// methods take and return data in host byte order, converting as necessary for the given
384    /// architecture.
385    pub struct ExtensionObjectPacket<'a> {
386        buf: Buffer<'a>,
387    }
388
389    impl<'a> ExtensionObjectPacket<'a> {
390        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
391            if packet.len() >= Self::minimum_packet_size() {
392                Ok(Self {
393                    buf: Buffer::Mutable(packet),
394                })
395            } else {
396                Err(Error::InsufficientPacketBuffer(
397                    String::from("ExtensionObjectPacket"),
398                    Self::minimum_packet_size(),
399                    packet.len(),
400                ))
401            }
402        }
403
404        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
405            if packet.len() >= Self::minimum_packet_size() {
406                Ok(Self {
407                    buf: Buffer::Immutable(packet),
408                })
409            } else {
410                Err(Error::InsufficientPacketBuffer(
411                    String::from("ExtensionObjectPacket"),
412                    Self::minimum_packet_size(),
413                    packet.len(),
414                ))
415            }
416        }
417
418        #[must_use]
419        pub const fn minimum_packet_size() -> usize {
420            4
421        }
422
423        pub fn set_length(&mut self, val: u16) {
424            self.buf.set_bytes(LENGTH_OFFSET, val.to_be_bytes());
425        }
426
427        pub fn set_class_num(&mut self, val: ClassNum) {
428            *self.buf.write(CLASS_NUM_OFFSET) = val.id();
429        }
430
431        pub fn set_class_subtype(&mut self, val: ClassSubType) {
432            *self.buf.write(CLASS_SUBTYPE_OFFSET) = val.0;
433        }
434
435        pub fn set_payload(&mut self, vals: &[u8]) {
436            let current_offset = Self::minimum_packet_size();
437            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
438                .copy_from_slice(vals);
439        }
440
441        #[must_use]
442        pub fn get_length(&self) -> u16 {
443            u16::from_be_bytes(self.buf.get_bytes(LENGTH_OFFSET))
444        }
445
446        #[must_use]
447        pub fn get_class_num(&self) -> ClassNum {
448            ClassNum::from(self.buf.read(CLASS_NUM_OFFSET))
449        }
450
451        #[must_use]
452        pub fn get_class_subtype(&self) -> ClassSubType {
453            ClassSubType::from(self.buf.read(CLASS_SUBTYPE_OFFSET))
454        }
455
456        #[must_use]
457        pub fn packet(&self) -> &[u8] {
458            self.buf.as_slice()
459        }
460
461        #[must_use]
462        pub fn payload(&self) -> &[u8] {
463            &self.buf.as_slice()[Self::minimum_packet_size()..usize::from(self.get_length())]
464        }
465    }
466
467    impl Debug for ExtensionObjectPacket<'_> {
468        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
469            f.debug_struct("ExtensionObject")
470                .field("length", &self.get_length())
471                .field("class_num", &self.get_class_num())
472                .field("class_subtype", &self.get_class_subtype())
473                .field("payload", &fmt_payload(self.payload()))
474                .finish()
475        }
476    }
477
478    #[cfg(test)]
479    mod tests {
480        use super::*;
481
482        #[test]
483        fn test_length() {
484            let mut buf = [0_u8; ExtensionObjectPacket::minimum_packet_size()];
485            let mut extension = ExtensionObjectPacket::new(&mut buf).unwrap();
486            extension.set_length(0);
487            assert_eq!(0, extension.get_length());
488            assert_eq!([0x00, 0x00], extension.packet()[0..=1]);
489            extension.set_length(8);
490            assert_eq!(8, extension.get_length());
491            assert_eq!([0x00, 0x08], extension.packet()[0..=1]);
492            extension.set_length(u16::MAX);
493            assert_eq!(u16::MAX, extension.get_length());
494            assert_eq!([0xFF, 0xFF], extension.packet()[0..=1]);
495        }
496
497        #[test]
498        fn test_class_num() {
499            let mut buf = [0_u8; ExtensionObjectPacket::minimum_packet_size()];
500            let mut extension = ExtensionObjectPacket::new(&mut buf).unwrap();
501            extension.set_class_num(ClassNum::MultiProtocolLabelSwitchingLabelStack);
502            assert_eq!(
503                ClassNum::MultiProtocolLabelSwitchingLabelStack,
504                extension.get_class_num()
505            );
506            assert_eq!([0x01], extension.packet()[2..3]);
507            extension.set_class_num(ClassNum::InterfaceInformationObject);
508            assert_eq!(
509                ClassNum::InterfaceInformationObject,
510                extension.get_class_num()
511            );
512            assert_eq!([0x02], extension.packet()[2..3]);
513            extension.set_class_num(ClassNum::InterfaceIdentificationObject);
514            assert_eq!(
515                ClassNum::InterfaceIdentificationObject,
516                extension.get_class_num()
517            );
518            assert_eq!([0x03], extension.packet()[2..3]);
519            extension.set_class_num(ClassNum::ExtendedInformation);
520            assert_eq!(ClassNum::ExtendedInformation, extension.get_class_num());
521            assert_eq!([0x04], extension.packet()[2..3]);
522            extension.set_class_num(ClassNum::Other(255));
523            assert_eq!(ClassNum::Other(255), extension.get_class_num());
524            assert_eq!([0xFF], extension.packet()[2..3]);
525        }
526
527        #[test]
528        fn test_class_subtype() {
529            let mut buf = [0_u8; ExtensionObjectPacket::minimum_packet_size()];
530            let mut extension = ExtensionObjectPacket::new(&mut buf).unwrap();
531            extension.set_class_subtype(ClassSubType(0));
532            assert_eq!(ClassSubType(0), extension.get_class_subtype());
533            assert_eq!([0x00], extension.packet()[3..4]);
534            extension.set_class_subtype(ClassSubType(1));
535            assert_eq!(ClassSubType(1), extension.get_class_subtype());
536            assert_eq!([0x01], extension.packet()[3..4]);
537            extension.set_class_subtype(ClassSubType(255));
538            assert_eq!(ClassSubType(255), extension.get_class_subtype());
539            assert_eq!([0xff], extension.packet()[3..4]);
540        }
541
542        #[test]
543        fn test_extension_header_view() {
544            let buf = [0x00, 0x08, 0x01, 0x01, 0x04, 0xbb, 0x41, 0x01];
545            let object = ExtensionObjectPacket::new_view(&buf).unwrap();
546            assert_eq!(8, object.get_length());
547            assert_eq!(
548                ClassNum::MultiProtocolLabelSwitchingLabelStack,
549                object.get_class_num()
550            );
551            assert_eq!(ClassSubType(1), object.get_class_subtype());
552            assert_eq!([0x04, 0xbb, 0x41, 0x01], object.payload());
553        }
554    }
555}
556
557pub mod mpls_label_stack {
558    use crate::buffer::Buffer;
559    use crate::error::{Error, Result};
560    use crate::icmp_extension::mpls_label_stack_member::MplsLabelStackMemberPacket;
561
562    /// Represents an ICMP `MplsLabelStackPacket`.
563    ///
564    /// The internal representation is held in network byte order (big-endian) and all accessor
565    /// methods take and return data in host byte order, converting as necessary for the given
566    /// architecture.
567    pub struct MplsLabelStackPacket<'a> {
568        buf: Buffer<'a>,
569    }
570
571    impl<'a> MplsLabelStackPacket<'a> {
572        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
573            if packet.len() >= Self::minimum_packet_size() {
574                Ok(Self {
575                    buf: Buffer::Mutable(packet),
576                })
577            } else {
578                Err(Error::InsufficientPacketBuffer(
579                    String::from("MplsLabelStackPacket"),
580                    Self::minimum_packet_size(),
581                    packet.len(),
582                ))
583            }
584        }
585
586        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
587            if packet.len() >= Self::minimum_packet_size() {
588                Ok(Self {
589                    buf: Buffer::Immutable(packet),
590                })
591            } else {
592                Err(Error::InsufficientPacketBuffer(
593                    String::from("MplsLabelStackPacket"),
594                    Self::minimum_packet_size(),
595                    packet.len(),
596                ))
597            }
598        }
599
600        #[must_use]
601        pub const fn minimum_packet_size() -> usize {
602            4
603        }
604
605        #[must_use]
606        pub fn packet(&self) -> &[u8] {
607            self.buf.as_slice()
608        }
609
610        #[must_use]
611        pub const fn members(&self) -> MplsLabelStackIter<'_> {
612            MplsLabelStackIter::new(&self.buf)
613        }
614    }
615
616    pub struct MplsLabelStackIter<'a> {
617        buf: &'a Buffer<'a>,
618        offset: usize,
619        bos: u8,
620    }
621
622    impl<'a> MplsLabelStackIter<'a> {
623        #[must_use]
624        pub const fn new(buf: &'a Buffer<'_>) -> Self {
625            Self {
626                buf,
627                offset: 0,
628                bos: 0,
629            }
630        }
631    }
632
633    impl<'a> Iterator for MplsLabelStackIter<'a> {
634        type Item = &'a [u8];
635
636        fn next(&mut self) -> Option<Self::Item> {
637            if self.bos > 0 || self.offset >= self.buf.as_slice().len() {
638                None
639            } else {
640                let member_bytes = &self.buf.as_slice()[self.offset..];
641                if let Ok(member) = MplsLabelStackMemberPacket::new_view(member_bytes) {
642                    self.bos = member.get_bos();
643                    self.offset += MplsLabelStackMemberPacket::minimum_packet_size();
644                    Some(member_bytes)
645                } else {
646                    None
647                }
648            }
649        }
650    }
651
652    #[cfg(test)]
653    mod tests {
654        use super::*;
655
656        #[test]
657        fn test_stack_member_iterator() {
658            let buf = [0x04, 0xbb, 0x41, 0x01];
659            let stack = MplsLabelStackPacket::new_view(&buf).unwrap();
660            let mut member_iter = stack.members();
661            let member_bytes = member_iter.next().unwrap();
662            let member = MplsLabelStackMemberPacket::new_view(member_bytes).unwrap();
663            assert_eq!(19380, member.get_label());
664            assert_eq!(0, member.get_exp());
665            assert_eq!(1, member.get_bos());
666            assert_eq!(1, member.get_ttl());
667            assert!(member_iter.next().is_none());
668        }
669    }
670}
671
672pub mod mpls_label_stack_member {
673    use crate::buffer::Buffer;
674    use crate::error::{Error, Result};
675    use std::fmt::{Debug, Formatter};
676
677    const LABEL_OFFSET: usize = 0;
678    const EXP_OFFSET: usize = 2;
679    const BOS_OFFSET: usize = 2;
680    const TTL_OFFSET: usize = 3;
681
682    /// Represents an ICMP `MplsLabelStackMemberPacket`.
683    ///
684    /// The internal representation is held in network byte order (big-endian) and all accessor
685    /// methods take and return data in host byte order, converting as necessary for the given
686    /// architecture.
687    pub struct MplsLabelStackMemberPacket<'a> {
688        buf: Buffer<'a>,
689    }
690
691    impl<'a> MplsLabelStackMemberPacket<'a> {
692        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
693            if packet.len() >= Self::minimum_packet_size() {
694                Ok(Self {
695                    buf: Buffer::Mutable(packet),
696                })
697            } else {
698                Err(Error::InsufficientPacketBuffer(
699                    String::from("MplsLabelStackMemberPacket"),
700                    Self::minimum_packet_size(),
701                    packet.len(),
702                ))
703            }
704        }
705
706        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
707            if packet.len() >= Self::minimum_packet_size() {
708                Ok(Self {
709                    buf: Buffer::Immutable(packet),
710                })
711            } else {
712                Err(Error::InsufficientPacketBuffer(
713                    String::from("MplsLabelStackMemberPacket"),
714                    Self::minimum_packet_size(),
715                    packet.len(),
716                ))
717            }
718        }
719
720        #[must_use]
721        pub const fn minimum_packet_size() -> usize {
722            4
723        }
724
725        #[must_use]
726        pub fn get_label(&self) -> u32 {
727            u32::from_be_bytes([
728                0x0,
729                self.buf.read(LABEL_OFFSET),
730                self.buf.read(LABEL_OFFSET + 1),
731                self.buf.read(LABEL_OFFSET + 2),
732            ]) >> 4
733        }
734
735        #[must_use]
736        pub fn get_exp(&self) -> u8 {
737            (self.buf.read(EXP_OFFSET) & 0x0e) >> 1
738        }
739
740        #[must_use]
741        pub fn get_bos(&self) -> u8 {
742            self.buf.read(BOS_OFFSET) & 0x01
743        }
744
745        #[must_use]
746        pub fn get_ttl(&self) -> u8 {
747            self.buf.read(TTL_OFFSET)
748        }
749
750        pub fn set_label(&mut self, val: u32) {
751            let bytes = (val << 4).to_be_bytes();
752            *self.buf.write(LABEL_OFFSET) = bytes[1];
753            *self.buf.write(LABEL_OFFSET + 1) = bytes[2];
754            *self.buf.write(LABEL_OFFSET + 2) =
755                (self.buf.read(LABEL_OFFSET + 2) & 0x0f) | (bytes[3] & 0xf0);
756        }
757
758        pub fn set_exp(&mut self, exp: u8) {
759            *self.buf.write(EXP_OFFSET) = (self.buf.read(EXP_OFFSET) & 0xf1) | ((exp << 1) & 0x0e);
760        }
761
762        pub fn set_bos(&mut self, bos: u8) {
763            *self.buf.write(BOS_OFFSET) = (self.buf.read(BOS_OFFSET) & 0xfe) | (bos & 0x01);
764        }
765
766        pub fn set_ttl(&mut self, ttl: u8) {
767            *self.buf.write(TTL_OFFSET) = ttl;
768        }
769
770        #[must_use]
771        pub fn packet(&self) -> &[u8] {
772            self.buf.as_slice()
773        }
774    }
775
776    impl Debug for MplsLabelStackMemberPacket<'_> {
777        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
778            f.debug_struct("MplsLabelStackMember")
779                .field("label", &self.get_label())
780                .field("exp", &self.get_exp())
781                .field("bos", &self.get_bos())
782                .field("ttl", &self.get_ttl())
783                .finish()
784        }
785    }
786
787    #[cfg(test)]
788    mod tests {
789        use super::*;
790
791        #[test]
792        fn test_label() {
793            let mut buf = [0_u8; MplsLabelStackMemberPacket::minimum_packet_size()];
794            let mut mpls_extension = MplsLabelStackMemberPacket::new(&mut buf).unwrap();
795            mpls_extension.set_label(0);
796            assert_eq!(0, mpls_extension.get_label());
797            assert_eq!([0x00, 0x00, 0x00], mpls_extension.packet()[0..3]);
798            mpls_extension.set_label(19380);
799            assert_eq!(19380, mpls_extension.get_label());
800            assert_eq!([0x04, 0xbb, 0x40], mpls_extension.packet()[0..3]);
801            mpls_extension.set_label(1_048_575);
802            assert_eq!(1_048_575, mpls_extension.get_label());
803            assert_eq!([0xff, 0xff, 0xf0], mpls_extension.packet()[0..3]);
804        }
805
806        #[test]
807        fn test_exp() {
808            let mut buf = [0_u8; MplsLabelStackMemberPacket::minimum_packet_size()];
809            let mut mpls_extension = MplsLabelStackMemberPacket::new(&mut buf).unwrap();
810            mpls_extension.set_exp(0);
811            assert_eq!(0, mpls_extension.get_exp());
812            assert_eq!([0x00], mpls_extension.packet()[2..3]);
813            mpls_extension.set_exp(7);
814            assert_eq!(7, mpls_extension.get_exp());
815            assert_eq!([0x0e], mpls_extension.packet()[2..3]);
816        }
817
818        #[test]
819        fn test_bos() {
820            let mut buf = [0_u8; MplsLabelStackMemberPacket::minimum_packet_size()];
821            let mut mpls_extension = MplsLabelStackMemberPacket::new(&mut buf).unwrap();
822            mpls_extension.set_bos(0);
823            assert_eq!(0, mpls_extension.get_bos());
824            assert_eq!([0x00], mpls_extension.packet()[2..3]);
825            mpls_extension.set_bos(1);
826            assert_eq!(1, mpls_extension.get_bos());
827            assert_eq!([0x01], mpls_extension.packet()[2..3]);
828        }
829
830        #[test]
831        fn test_ttl() {
832            let mut buf = [0_u8; MplsLabelStackMemberPacket::minimum_packet_size()];
833            let mut mpls_extension = MplsLabelStackMemberPacket::new(&mut buf).unwrap();
834            mpls_extension.set_ttl(0);
835            assert_eq!(0, mpls_extension.get_ttl());
836            assert_eq!([0x00], mpls_extension.packet()[3..4]);
837            mpls_extension.set_ttl(1);
838            assert_eq!(1, mpls_extension.get_ttl());
839            assert_eq!([0x01], mpls_extension.packet()[3..4]);
840            mpls_extension.set_ttl(255);
841            assert_eq!(255, mpls_extension.get_ttl());
842            assert_eq!([0xff], mpls_extension.packet()[3..4]);
843        }
844
845        #[test]
846        fn test_combined() {
847            let mut buf = [0_u8; MplsLabelStackMemberPacket::minimum_packet_size()];
848            let mut mpls_extension = MplsLabelStackMemberPacket::new(&mut buf).unwrap();
849            mpls_extension.set_label(19380);
850            mpls_extension.set_exp(0);
851            mpls_extension.set_bos(1);
852            mpls_extension.set_ttl(1);
853            assert_eq!(19380, mpls_extension.get_label());
854            assert_eq!(0, mpls_extension.get_exp());
855            assert_eq!(1, mpls_extension.get_bos());
856            assert_eq!(1, mpls_extension.get_ttl());
857            assert_eq!([0x04, 0xbb, 0x41, 0x01], mpls_extension.packet()[0..4]);
858            mpls_extension.set_label(1_048_575);
859            mpls_extension.set_exp(7);
860            mpls_extension.set_bos(1);
861            mpls_extension.set_ttl(255);
862            assert_eq!(1_048_575, mpls_extension.get_label());
863            assert_eq!(7, mpls_extension.get_exp());
864            assert_eq!(1, mpls_extension.get_bos());
865            assert_eq!(255, mpls_extension.get_ttl());
866            assert_eq!([0xff, 0xff, 0xff, 0xff], mpls_extension.packet()[0..4]);
867        }
868
869        #[test]
870        fn test_view() {
871            let buf = [0x04, 0xbb, 0x41, 0x01];
872            let object = MplsLabelStackMemberPacket::new_view(&buf).unwrap();
873            assert_eq!(19380, object.get_label());
874            assert_eq!(0, object.get_exp());
875            assert_eq!(1, object.get_bos());
876            assert_eq!(1, object.get_ttl());
877        }
878    }
879}
880
881pub mod extension_splitter {
882    use crate::icmp_extension::extension_header::ExtensionHeaderPacket;
883    const MIN_HEADER: usize = ExtensionHeaderPacket::minimum_packet_size();
884
885    /// From rfc4884 (section 3) entitled "Summary of Changes to ICMP":
886    ///
887    /// "When the ICMP Extension Structure is appended to an ICMP message
888    /// and that ICMP message contains an "original datagram" field, the
889    /// "original datagram" field MUST contain at least 128 octets."
890    const ICMP_ORIG_DATAGRAM_MIN_LENGTH: usize = 128;
891
892    /// Separate an ICMP payload from ICMP extensions as defined in rfc4884.
893    ///
894    /// Applies to `TimeExceeded` and `DestinationUnreachable` ICMP messages only.
895    #[must_use]
896    pub fn split(length: usize, icmp_payload: &[u8]) -> (&[u8], Option<&[u8]>) {
897        // If the rfc4884 length field provided is larger than the payload length then
898        // the full payload is returned without any extension.
899        if length > icmp_payload.len() {
900            return (icmp_payload, None);
901        }
902        if icmp_payload.len() > ICMP_ORIG_DATAGRAM_MIN_LENGTH {
903            if length > ICMP_ORIG_DATAGRAM_MIN_LENGTH {
904                // a 'compliant' ICMP extension longer than 128 octets.
905                match icmp_payload.split_at(length) {
906                    (payload, extension) if extension.len() >= MIN_HEADER => {
907                        (payload, Some(extension))
908                    }
909                    _ => (icmp_payload, None),
910                }
911            } else if length > 0 {
912                // a 'compliant' ICMP extension padded to at least 128 octets,
913                // so we trim the original datagram to rfc4884 length.
914                match icmp_payload.split_at(ICMP_ORIG_DATAGRAM_MIN_LENGTH) {
915                    (payload, extension) if extension.len() >= MIN_HEADER => {
916                        (&payload[..length], Some(extension))
917                    }
918                    _ => (icmp_payload, None),
919                }
920            } else {
921                // a 'non-compliant' ICMP extension padded to 128 octets.
922                match icmp_payload.split_at(ICMP_ORIG_DATAGRAM_MIN_LENGTH) {
923                    (payload, extension) if extension.len() >= MIN_HEADER => {
924                        (payload, Some(extension))
925                    }
926                    _ => (icmp_payload, None),
927                }
928            }
929        } else {
930            // no extension present
931            (icmp_payload, None)
932        }
933    }
934
935    #[cfg(test)]
936    mod tests {
937        use super::*;
938        use crate::icmp_extension::extension_header::ExtensionHeaderPacket;
939        use crate::icmp_extension::extension_object::{
940            ClassNum, ClassSubType, ExtensionObjectPacket,
941        };
942        use crate::icmp_extension::extension_structure::ExtensionsPacket;
943        use crate::icmp_extension::mpls_label_stack::MplsLabelStackPacket;
944        use crate::icmp_extension::mpls_label_stack_member::MplsLabelStackMemberPacket;
945
946        #[test]
947        fn test_split_empty_payload() {
948            let icmp_payload: [u8; 0] = [];
949            let (payload, extension) = split(0, &icmp_payload);
950            assert!(payload.is_empty() && extension.is_none());
951        }
952
953        // Test ICMP payload which is 12 bytes and has rfc4884 length of 3 (12
954        // bytes) so payload is 12 bytes and there is no extension.
955        #[test]
956        fn test_split_payload_with_compliant_empty_extension() {
957            let icmp_payload: [u8; 12] = [0; 12];
958            let (payload, extension) = split(3 * 4, &icmp_payload);
959            assert_eq!(payload, &[0; 12]);
960            assert_eq!(extension, None);
961        }
962
963        // Test ICMP payload with a minimal compliant extension.
964        #[test]
965        fn test_split_payload_with_compliant_minimal_extension() {
966            let icmp_payload: [u8; 132] = [0; 132];
967            let (payload, extension) = split(32 * 4, &icmp_payload);
968            assert_eq!(payload, &[0; 128]);
969            assert_eq!(extension, Some([0; 4].as_slice()));
970        }
971
972        // Test handling of an ICMP payload which has a rfc4884 length that
973        // is longer than the original datagram.
974        //
975        // For such invalid packets we assume there is no extension.
976        #[test]
977        fn test_split_payload_with_invalid_rfc4884_length() {
978            let icmp_payload: [u8; 128] = [0; 128];
979            let (payload, extension) = split(33 * 4, &icmp_payload);
980            assert_eq!(payload, &[0; 128]);
981            assert!(extension.is_none());
982        }
983
984        // Test handling of an ICMP payload which has a compliant extension
985        // which is not as long as the minimum size for an ICMP extension
986        // header (4 bytes).
987        //
988        // For such invalid packets we assume there is no extension.
989        #[test]
990        fn test_split_payload_with_compliant_invalid_extension() {
991            let icmp_payload: [u8; 129] = [0; 129];
992            let (payload, extension) = split(32 * 4, &icmp_payload);
993            assert_eq!(payload, &[0; 129]);
994            assert!(extension.is_none());
995        }
996
997        mod ipv4 {
998            use super::*;
999            use crate::icmpv4::echo_request::EchoRequestPacket;
1000            use crate::icmpv4::time_exceeded::TimeExceededPacket;
1001            use crate::icmpv4::{IcmpCode, IcmpType};
1002            use crate::ipv4::Ipv4Packet;
1003            use std::net::Ipv4Addr;
1004
1005            // This ICMP `TimeExceeded` packet which contains single `MPLS` extension
1006            // object with a single member.  The packet does not have a `length`
1007            // field and is therefore rfc4884 non-complaint.
1008            #[test]
1009            #[allow(clippy::cognitive_complexity)]
1010            fn test_split_extension_ipv4_time_exceeded_non_compliant_mpls() {
1011                let buf = hex_literal::hex!(
1012                    "
1013                   0b 00 f4 ff 00 00 00 00 45 00 00 54 cc 1c 40 00
1014                   01 01 b5 f4 c0 a8 01 15 5d b8 d8 22 08 00 0f e3
1015                   65 da 82 42 00 00 00 00 00 00 00 00 00 00 00 00
1016                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1017                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1018                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1019                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1020                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1021                   00 00 00 00 00 00 00 00 20 00 99 3a 00 08 01 01
1022                   04 bb 41 01
1023                   "
1024                );
1025                let time_exceeded_packet = TimeExceededPacket::new_view(&buf).unwrap();
1026                assert_eq!(IcmpType::TimeExceeded, time_exceeded_packet.get_icmp_type());
1027                assert_eq!(IcmpCode(0), time_exceeded_packet.get_icmp_code());
1028                assert_eq!(62719, time_exceeded_packet.get_checksum());
1029                assert_eq!(0, time_exceeded_packet.get_length());
1030                assert_eq!(&buf[8..136], time_exceeded_packet.payload());
1031                assert_eq!(Some(&buf[136..]), time_exceeded_packet.extension());
1032
1033                let nested_ipv4 = Ipv4Packet::new_view(time_exceeded_packet.payload()).unwrap();
1034                assert_eq!(Ipv4Addr::from([192, 168, 1, 21]), nested_ipv4.get_source());
1035                assert_eq!(
1036                    Ipv4Addr::from([93, 184, 216, 34]),
1037                    nested_ipv4.get_destination()
1038                );
1039                assert_eq!(&buf[28..136], nested_ipv4.payload());
1040
1041                let nested_echo = EchoRequestPacket::new_view(nested_ipv4.payload()).unwrap();
1042                assert_eq!(IcmpCode(0), nested_echo.get_icmp_code());
1043                assert_eq!(IcmpType::EchoRequest, nested_echo.get_icmp_type());
1044                assert_eq!(0x0FE3, nested_echo.get_checksum());
1045                assert_eq!(26074, nested_echo.get_identifier());
1046                assert_eq!(33346, nested_echo.get_sequence());
1047                assert_eq!(&buf[36..136], nested_echo.payload());
1048
1049                let extensions =
1050                    ExtensionsPacket::new_view(time_exceeded_packet.extension().unwrap()).unwrap();
1051
1052                let extension_header =
1053                    ExtensionHeaderPacket::new_view(extensions.header()).unwrap();
1054                assert_eq!(2, extension_header.get_version());
1055                assert_eq!(0x993A, extension_header.get_checksum());
1056
1057                let object_bytes = extensions.objects().next().unwrap();
1058                let extension_object = ExtensionObjectPacket::new_view(object_bytes).unwrap();
1059
1060                assert_eq!(8, extension_object.get_length());
1061                assert_eq!(
1062                    ClassNum::MultiProtocolLabelSwitchingLabelStack,
1063                    extension_object.get_class_num()
1064                );
1065                assert_eq!(ClassSubType(1), extension_object.get_class_subtype());
1066                assert_eq!([0x04, 0xbb, 0x41, 0x01], extension_object.payload());
1067
1068                let mpls_stack =
1069                    MplsLabelStackPacket::new_view(extension_object.payload()).unwrap();
1070                let mpls_stack_member_bytes = mpls_stack.members().next().unwrap();
1071                let mpls_stack_member =
1072                    MplsLabelStackMemberPacket::new_view(mpls_stack_member_bytes).unwrap();
1073                assert_eq!(19380, mpls_stack_member.get_label());
1074                assert_eq!(0, mpls_stack_member.get_exp());
1075                assert_eq!(1, mpls_stack_member.get_bos());
1076                assert_eq!(1, mpls_stack_member.get_ttl());
1077            }
1078
1079            // This ICMP `TimeExceeded` packet does not have any ICMP extensions.
1080            // It has a rfc4884 complaint `length` field.
1081            #[test]
1082            fn test_split_extension_ipv4_time_exceeded_compliant_no_extension() {
1083                let buf = hex_literal::hex!(
1084                    "
1085                   0b 00 f4 ee 00 11 00 00 45 00 00 54 a2 ee 40 00
1086                   01 01 df 22 c0 a8 01 15 5d b8 d8 22 08 00 0f e1
1087                   65 da 82 44 00 00 00 00 00 00 00 00 00 00 00 00
1088                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1089                   00 00 00 00 00 00 00 00 00 00 00 00
1090                   "
1091                );
1092                let time_exceeded_packet = TimeExceededPacket::new_view(&buf).unwrap();
1093                assert_eq!(IcmpType::TimeExceeded, time_exceeded_packet.get_icmp_type());
1094                assert_eq!(IcmpCode(0), time_exceeded_packet.get_icmp_code());
1095                assert_eq!(62702, time_exceeded_packet.get_checksum());
1096                assert_eq!(17, time_exceeded_packet.get_length());
1097                assert_eq!(&buf[8..76], time_exceeded_packet.payload());
1098                assert_eq!(None, time_exceeded_packet.extension());
1099
1100                let nested_ipv4 = Ipv4Packet::new_view(&buf[8..76]).unwrap();
1101                assert_eq!(Ipv4Addr::from([192, 168, 1, 21]), nested_ipv4.get_source());
1102                assert_eq!(
1103                    Ipv4Addr::from([93, 184, 216, 34]),
1104                    nested_ipv4.get_destination()
1105                );
1106                assert_eq!(&buf[28..76], nested_ipv4.payload());
1107
1108                let nested_echo = EchoRequestPacket::new_view(nested_ipv4.payload()).unwrap();
1109                assert_eq!(IcmpCode(0), nested_echo.get_icmp_code());
1110                assert_eq!(IcmpType::EchoRequest, nested_echo.get_icmp_type());
1111                assert_eq!(0x0FE1, nested_echo.get_checksum());
1112                assert_eq!(26074, nested_echo.get_identifier());
1113                assert_eq!(33348, nested_echo.get_sequence());
1114                assert_eq!(&buf[36..76], nested_echo.payload());
1115            }
1116
1117            // This is a real example that was observed in the wild whilst testing.
1118            //
1119            // It has a rfc4884 complaint `length` field set to be 17 and so has
1120            // an original datagram if length 68 octet (17 * 4 = 68) but is padded
1121            // to be 128 octets.
1122            //
1123            // See `https://github.com/fujiapple852/trippy/issues/804` for further
1124            // discussion and analysis of this case.
1125            #[test]
1126            fn test_split_extension_ipv4_time_exceeded_compliant_extension() {
1127                let buf = hex_literal::hex!(
1128                    "
1129                   0b 00 f4 ee 00 11 00 00 45 00 00 54 20 c3 40 00
1130                   02 01 b5 7e 64 63 08 2a 5d b8 d8 22 08 00 11 8d
1131                   65 83 80 ef 00 00 00 00 00 00 00 00 00 00 00 00
1132                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1133                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1134                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1135                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1136                   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1137                   00 00 00 00 00 00 00 00 20 00 78 56 00 08 01 01
1138                   65 9f 01 01
1139                   "
1140                );
1141                let time_exceeded_packet = TimeExceededPacket::new_view(&buf).unwrap();
1142                assert_eq!(68, time_exceeded_packet.payload().len());
1143                assert_eq!(12, time_exceeded_packet.extension().unwrap().len());
1144                let extensions =
1145                    ExtensionsPacket::new_view(time_exceeded_packet.extension().unwrap()).unwrap();
1146
1147                let extension_header =
1148                    ExtensionHeaderPacket::new_view(extensions.header()).unwrap();
1149                assert_eq!(2, extension_header.get_version());
1150                assert_eq!(0x7856, extension_header.get_checksum());
1151
1152                let object_bytes = extensions.objects().next().unwrap();
1153                let extension_object = ExtensionObjectPacket::new_view(object_bytes).unwrap();
1154
1155                assert_eq!(8, extension_object.get_length());
1156                assert_eq!(
1157                    ClassNum::MultiProtocolLabelSwitchingLabelStack,
1158                    extension_object.get_class_num()
1159                );
1160                assert_eq!(ClassSubType(1), extension_object.get_class_subtype());
1161                assert_eq!([0x65, 0x9f, 0x01, 0x01], extension_object.payload());
1162
1163                let mpls_stack =
1164                    MplsLabelStackPacket::new_view(extension_object.payload()).unwrap();
1165                let mpls_stack_member_bytes = mpls_stack.members().next().unwrap();
1166                let mpls_stack_member =
1167                    MplsLabelStackMemberPacket::new_view(mpls_stack_member_bytes).unwrap();
1168                assert_eq!(416_240, mpls_stack_member.get_label());
1169                assert_eq!(0, mpls_stack_member.get_exp());
1170                assert_eq!(1, mpls_stack_member.get_bos());
1171                assert_eq!(1, mpls_stack_member.get_ttl());
1172            }
1173        }
1174
1175        mod ipv6 {
1176            use crate::icmp_extension::extension_header::ExtensionHeaderPacket;
1177            use crate::icmp_extension::extension_object::{
1178                ClassNum, ClassSubType, ExtensionObjectPacket,
1179            };
1180            use crate::icmp_extension::extension_structure::ExtensionsPacket;
1181            use crate::icmp_extension::mpls_label_stack::MplsLabelStackPacket;
1182            use crate::icmp_extension::mpls_label_stack_member::MplsLabelStackMemberPacket;
1183            use crate::icmpv6::echo_request::EchoRequestPacket;
1184            use crate::icmpv6::time_exceeded::TimeExceededPacket;
1185            use crate::icmpv6::{IcmpCode, IcmpType};
1186            use crate::ipv6::Ipv6Packet;
1187
1188            // Real IPv6 example with a rfc4884 length of 10 (10 * 8 = 80
1189            // octets).
1190            //
1191            // This example contain an MPLS extension stack which contains
1192            // two member (i.e. labels)
1193            #[test]
1194            #[allow(clippy::cognitive_complexity)]
1195            fn test_ipv6() {
1196                let buf = hex_literal::hex!(
1197                    "
1198                    03 00 be a8 0a 00 00 00 68 04 83 fe 00 2c 3a 01
1199                    24 00 61 80 00 00 00 d0 00 00 00 00 12 65 b0 01
1200                    24 04 68 00 40 03 0c 1c 00 00 00 00 00 00 00 8a
1201                    80 00 b2 e1 2a 60 80 f2 00 00 00 00 00 00 00 00
1202                    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1203                    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1204                    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1205                    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1206                    00 00 00 00 00 00 00 00 20 00 96 53 00 0c 01 01
1207                    06 9f 18 01 00 00 29 ff
1208                    "
1209                );
1210                let time_exceeded_packet = TimeExceededPacket::new_view(&buf).unwrap();
1211                assert_eq!(IcmpType::TimeExceeded, time_exceeded_packet.get_icmp_type());
1212                assert_eq!(IcmpCode(0), time_exceeded_packet.get_icmp_code());
1213                assert_eq!(48808, time_exceeded_packet.get_checksum());
1214                assert_eq!(10, time_exceeded_packet.get_length());
1215                assert_eq!(&buf[8..88], time_exceeded_packet.payload());
1216                assert_eq!(Some(&buf[136..]), time_exceeded_packet.extension());
1217                assert_eq!(80, time_exceeded_packet.payload().len());
1218                assert_eq!(16, time_exceeded_packet.extension().unwrap().len());
1219
1220                let nested_ipv6 = Ipv6Packet::new_view(time_exceeded_packet.payload()).unwrap();
1221                let nested_echo = EchoRequestPacket::new_view(nested_ipv6.payload()).unwrap();
1222                assert_eq!(IcmpCode(0), nested_echo.get_icmp_code());
1223                assert_eq!(IcmpType::EchoRequest, nested_echo.get_icmp_type());
1224                assert_eq!(0xB2E1, nested_echo.get_checksum());
1225                assert_eq!(10848, nested_echo.get_identifier());
1226                assert_eq!(33010, nested_echo.get_sequence());
1227
1228                let extensions =
1229                    ExtensionsPacket::new_view(time_exceeded_packet.extension().unwrap()).unwrap();
1230
1231                let extension_header =
1232                    ExtensionHeaderPacket::new_view(extensions.header()).unwrap();
1233                assert_eq!(2, extension_header.get_version());
1234                assert_eq!(0x9653, extension_header.get_checksum());
1235
1236                let object_bytes = extensions.objects().next().unwrap();
1237                let extension_object = ExtensionObjectPacket::new_view(object_bytes).unwrap();
1238                assert_eq!(12, extension_object.get_length());
1239                assert_eq!(
1240                    ClassNum::MultiProtocolLabelSwitchingLabelStack,
1241                    extension_object.get_class_num()
1242                );
1243                assert_eq!(ClassSubType(1), extension_object.get_class_subtype());
1244                assert_eq!(
1245                    [0x06, 0x9f, 0x18, 0x01, 0x00, 0x00, 0x29, 0xff],
1246                    extension_object.payload()
1247                );
1248
1249                let mpls_stack =
1250                    MplsLabelStackPacket::new_view(extension_object.payload()).unwrap();
1251                let mut mpls_stack_member_iter = mpls_stack.members();
1252
1253                // 1st stack member
1254                let mpls_stack_member_bytes = mpls_stack_member_iter.next().unwrap();
1255                let mpls_stack_member =
1256                    MplsLabelStackMemberPacket::new_view(mpls_stack_member_bytes).unwrap();
1257                assert_eq!(27121, mpls_stack_member.get_label());
1258                assert_eq!(4, mpls_stack_member.get_exp());
1259                assert_eq!(0, mpls_stack_member.get_bos());
1260                assert_eq!(1, mpls_stack_member.get_ttl());
1261
1262                // 2nd stack member
1263                let mpls_stack_member_bytes = mpls_stack_member_iter.next().unwrap();
1264                let mpls_stack_member =
1265                    MplsLabelStackMemberPacket::new_view(mpls_stack_member_bytes).unwrap();
1266                assert_eq!(2, mpls_stack_member.get_label());
1267                assert_eq!(4, mpls_stack_member.get_exp());
1268                assert_eq!(1, mpls_stack_member.get_bos());
1269                assert_eq!(255, mpls_stack_member.get_ttl());
1270                assert!(mpls_stack_member_iter.next().is_none());
1271            }
1272
1273            // Real IPv6 example with a rfc4884 length of 16 (16 * 8 = 128
1274            // octets for) but the total payload is only 84 octets and
1275            // therefore this is a malformed packet.
1276            //
1277            // For such packets Trippy assumes there are no extensions.
1278            #[test]
1279            fn test_ipv6_2() {
1280                let buf = hex_literal::hex!(
1281                    "
1282                    03 00 5a b4 10 00 00 00 68 0e 0d 91 00 2c 3a 01
1283                    24 00 61 80 00 00 00 d0 00 00 00 00 12 65 b0 01
1284                    24 04 68 00 40 03 0c 05 00 00 00 00 00 00 00 71
1285                    80 00 a8 e7 34 88 80 f4 00 00 00 00 00 00 00 00
1286                    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1287                    00 00 00 00 00 00 00 00 00 00 00 00
1288                    "
1289                );
1290                let time_exceeded_packet = TimeExceededPacket::new_view(&buf).unwrap();
1291                assert_eq!(84, time_exceeded_packet.payload().len());
1292                assert_eq!(None, time_exceeded_packet.extension());
1293
1294                let nested_ipv6 = Ipv6Packet::new_view(time_exceeded_packet.payload()).unwrap();
1295                let nested_echo = EchoRequestPacket::new_view(nested_ipv6.payload()).unwrap();
1296                assert_eq!(IcmpCode(0), nested_echo.get_icmp_code());
1297                assert_eq!(IcmpType::EchoRequest, nested_echo.get_icmp_type());
1298                assert_eq!(0xA8E7, nested_echo.get_checksum());
1299                assert_eq!(13448, nested_echo.get_identifier());
1300                assert_eq!(33012, nested_echo.get_sequence());
1301            }
1302        }
1303    }
1304}