Skip to main content

trippy_packet/
icmpv4.rs

1use crate::buffer::Buffer;
2use crate::error::{Error, Result};
3use std::fmt::{Debug, Formatter};
4
5/// The type of ICMP packet.
6#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
7pub enum IcmpType {
8    EchoRequest,
9    EchoReply,
10    DestinationUnreachable,
11    TimeExceeded,
12    Other(u8),
13}
14
15impl IcmpType {
16    #[must_use]
17    pub const fn id(&self) -> u8 {
18        match self {
19            Self::EchoRequest => 8,
20            Self::EchoReply => 0,
21            Self::DestinationUnreachable => 3,
22            Self::TimeExceeded => 11,
23            Self::Other(id) => *id,
24        }
25    }
26}
27
28impl From<u8> for IcmpType {
29    fn from(val: u8) -> Self {
30        match val {
31            8 => Self::EchoRequest,
32            0 => Self::EchoReply,
33            3 => Self::DestinationUnreachable,
34            11 => Self::TimeExceeded,
35            id => Self::Other(id),
36        }
37    }
38}
39
40/// The ICMP code.
41#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
42pub struct IcmpCode(pub u8);
43
44impl From<u8> for IcmpCode {
45    fn from(val: u8) -> Self {
46        Self(val)
47    }
48}
49
50/// The code for `TimeExceeded` ICMP packet type.
51#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
52pub enum IcmpTimeExceededCode {
53    /// TTL expired in transit.
54    TtlExpired,
55    /// Fragment reassembly time exceeded.
56    FragmentReassembly,
57    /// An unknown code.
58    Unknown(u8),
59}
60
61impl From<IcmpCode> for IcmpTimeExceededCode {
62    fn from(val: IcmpCode) -> Self {
63        match val {
64            IcmpCode(0) => Self::TtlExpired,
65            IcmpCode(1) => Self::FragmentReassembly,
66            IcmpCode(id) => Self::Unknown(id),
67        }
68    }
69}
70
71const TYPE_OFFSET: usize = 0;
72const CODE_OFFSET: usize = 1;
73const CHECKSUM_OFFSET: usize = 2;
74
75/// Represents an ICMP packet.
76///
77/// The internal representation is held in network byte order (big-endian) and all accessor methods
78/// take and return data in host byte order, converting as necessary for the given architecture.
79pub struct IcmpPacket<'a> {
80    buf: Buffer<'a>,
81}
82
83impl<'a> IcmpPacket<'a> {
84    pub fn new(packet: &'a mut [u8]) -> Result<Self> {
85        if packet.len() >= Self::minimum_packet_size() {
86            Ok(Self {
87                buf: Buffer::Mutable(packet),
88            })
89        } else {
90            Err(Error::InsufficientPacketBuffer(
91                String::from("IcmpPacket"),
92                Self::minimum_packet_size(),
93                packet.len(),
94            ))
95        }
96    }
97
98    pub fn new_view(packet: &'a [u8]) -> Result<Self> {
99        if packet.len() >= Self::minimum_packet_size() {
100            Ok(Self {
101                buf: Buffer::Immutable(packet),
102            })
103        } else {
104            Err(Error::InsufficientPacketBuffer(
105                String::from("IcmpPacket"),
106                Self::minimum_packet_size(),
107                packet.len(),
108            ))
109        }
110    }
111
112    #[must_use]
113    pub const fn minimum_packet_size() -> usize {
114        8
115    }
116
117    #[must_use]
118    pub fn get_icmp_type(&self) -> IcmpType {
119        IcmpType::from(self.buf.read(TYPE_OFFSET))
120    }
121
122    #[must_use]
123    pub fn get_icmp_code(&self) -> IcmpCode {
124        IcmpCode::from(self.buf.read(CODE_OFFSET))
125    }
126
127    #[must_use]
128    pub fn get_checksum(&self) -> u16 {
129        u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
130    }
131
132    pub fn set_icmp_type(&mut self, val: IcmpType) {
133        *self.buf.write(TYPE_OFFSET) = val.id();
134    }
135
136    pub fn set_icmp_code(&mut self, val: IcmpCode) {
137        *self.buf.write(CODE_OFFSET) = val.0;
138    }
139
140    pub fn set_checksum(&mut self, val: u16) {
141        self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
142    }
143
144    #[must_use]
145    pub fn packet(&self) -> &[u8] {
146        self.buf.as_slice()
147    }
148}
149
150impl Debug for IcmpPacket<'_> {
151    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152        f.debug_struct("IcmpPacket")
153            .field("icmp_type", &self.get_icmp_type())
154            .field("icmp_code", &self.get_icmp_code())
155            .field("checksum", &self.get_checksum())
156            .finish()
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn test_icmp_type() {
166        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
167        let mut packet = IcmpPacket::new(&mut buf).unwrap();
168        packet.set_icmp_type(IcmpType::EchoRequest);
169        assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
170        assert_eq!([0x08], packet.packet()[0..1]);
171        packet.set_icmp_type(IcmpType::EchoReply);
172        assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
173        assert_eq!([0x00], packet.packet()[0..1]);
174        packet.set_icmp_type(IcmpType::DestinationUnreachable);
175        assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
176        assert_eq!([0x03], packet.packet()[0..1]);
177        packet.set_icmp_type(IcmpType::TimeExceeded);
178        assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
179        assert_eq!([0x0B], packet.packet()[0..1]);
180        packet.set_icmp_type(IcmpType::Other(255));
181        assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
182        assert_eq!([0xFF], packet.packet()[0..1]);
183    }
184
185    #[test]
186    fn test_icmp_code() {
187        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
188        let mut packet = IcmpPacket::new(&mut buf).unwrap();
189        packet.set_icmp_code(IcmpCode(0));
190        assert_eq!(IcmpCode(0), packet.get_icmp_code());
191        assert_eq!([0x00], packet.packet()[1..2]);
192        packet.set_icmp_code(IcmpCode(5));
193        assert_eq!(IcmpCode(5), packet.get_icmp_code());
194        assert_eq!([0x05], packet.packet()[1..2]);
195        packet.set_icmp_code(IcmpCode(255));
196        assert_eq!(IcmpCode(255), packet.get_icmp_code());
197        assert_eq!([0xFF], packet.packet()[1..2]);
198    }
199
200    #[test]
201    fn test_checksum() {
202        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
203        let mut packet = IcmpPacket::new(&mut buf).unwrap();
204        packet.set_checksum(0);
205        assert_eq!(0, packet.get_checksum());
206        assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
207        packet.set_checksum(1999);
208        assert_eq!(1999, packet.get_checksum());
209        assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
210        packet.set_checksum(u16::MAX);
211        assert_eq!(u16::MAX, packet.get_checksum());
212        assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
213    }
214
215    #[test]
216    fn test_new_insufficient_buffer() {
217        const SIZE: usize = IcmpPacket::minimum_packet_size();
218        let mut buf = [0_u8; SIZE - 1];
219        let err = IcmpPacket::new(&mut buf).unwrap_err();
220        assert_eq!(
221            Error::InsufficientPacketBuffer(String::from("IcmpPacket"), SIZE, SIZE - 1),
222            err
223        );
224    }
225
226    #[test]
227    fn test_new_view_insufficient_buffer() {
228        const SIZE: usize = IcmpPacket::minimum_packet_size();
229        let buf = [0_u8; SIZE - 1];
230        let err = IcmpPacket::new_view(&buf).unwrap_err();
231        assert_eq!(
232            Error::InsufficientPacketBuffer(String::from("IcmpPacket"), SIZE, SIZE - 1),
233            err
234        );
235    }
236}
237
238pub mod echo_request {
239    use crate::buffer::Buffer;
240    use crate::error::{Error, Result};
241    use crate::fmt_payload;
242    use crate::icmpv4::{IcmpCode, IcmpType};
243    use std::fmt::{Debug, Formatter};
244
245    const TYPE_OFFSET: usize = 0;
246    const CODE_OFFSET: usize = 1;
247    const CHECKSUM_OFFSET: usize = 2;
248    const IDENTIFIER_OFFSET: usize = 4;
249    const SEQUENCE_OFFSET: usize = 6;
250
251    /// Represents an ICMP `EchoRequest` packet.
252    ///
253    /// The internal representation is held in network byte order (big-endian) and all accessor
254    /// methods take and return data in host byte order, converting as necessary for the given
255    /// architecture.
256    pub struct EchoRequestPacket<'a> {
257        buf: Buffer<'a>,
258    }
259
260    impl<'a> EchoRequestPacket<'a> {
261        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
262            if packet.len() >= Self::minimum_packet_size() {
263                Ok(Self {
264                    buf: Buffer::Mutable(packet),
265                })
266            } else {
267                Err(Error::InsufficientPacketBuffer(
268                    String::from("EchoRequestPacket"),
269                    Self::minimum_packet_size(),
270                    packet.len(),
271                ))
272            }
273        }
274
275        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
276            if packet.len() >= Self::minimum_packet_size() {
277                Ok(Self {
278                    buf: Buffer::Immutable(packet),
279                })
280            } else {
281                Err(Error::InsufficientPacketBuffer(
282                    String::from("EchoRequestPacket"),
283                    Self::minimum_packet_size(),
284                    packet.len(),
285                ))
286            }
287        }
288
289        #[must_use]
290        pub const fn minimum_packet_size() -> usize {
291            8
292        }
293
294        #[must_use]
295        pub fn get_icmp_type(&self) -> IcmpType {
296            IcmpType::from(self.buf.read(TYPE_OFFSET))
297        }
298
299        #[must_use]
300        pub fn get_icmp_code(&self) -> IcmpCode {
301            IcmpCode::from(self.buf.read(CODE_OFFSET))
302        }
303
304        #[must_use]
305        pub fn get_checksum(&self) -> u16 {
306            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
307        }
308
309        #[must_use]
310        pub fn get_identifier(&self) -> u16 {
311            u16::from_be_bytes(self.buf.get_bytes(IDENTIFIER_OFFSET))
312        }
313
314        #[must_use]
315        pub fn get_sequence(&self) -> u16 {
316            u16::from_be_bytes(self.buf.get_bytes(SEQUENCE_OFFSET))
317        }
318
319        pub fn set_icmp_type(&mut self, val: IcmpType) {
320            *self.buf.write(TYPE_OFFSET) = val.id();
321        }
322
323        pub fn set_icmp_code(&mut self, val: IcmpCode) {
324            *self.buf.write(CODE_OFFSET) = val.0;
325        }
326
327        pub fn set_checksum(&mut self, val: u16) {
328            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
329        }
330
331        pub fn set_identifier(&mut self, val: u16) {
332            self.buf.set_bytes(IDENTIFIER_OFFSET, val.to_be_bytes());
333        }
334
335        pub fn set_sequence(&mut self, val: u16) {
336            self.buf.set_bytes(SEQUENCE_OFFSET, val.to_be_bytes());
337        }
338
339        pub fn set_payload(&mut self, vals: &[u8]) {
340            let current_offset = Self::minimum_packet_size();
341            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
342                .copy_from_slice(vals);
343        }
344
345        #[must_use]
346        pub fn packet(&self) -> &[u8] {
347            self.buf.as_slice()
348        }
349
350        #[must_use]
351        pub fn payload(&self) -> &[u8] {
352            &self.buf.as_slice()[Self::minimum_packet_size()..]
353        }
354    }
355
356    impl Debug for EchoRequestPacket<'_> {
357        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
358            f.debug_struct("EchoRequestPacket")
359                .field("icmp_type", &self.get_icmp_type())
360                .field("icmp_code", &self.get_icmp_code())
361                .field("checksum", &self.get_checksum())
362                .field("identifier", &self.get_identifier())
363                .field("sequence", &self.get_sequence())
364                .field("payload", &fmt_payload(self.payload()))
365                .finish()
366        }
367    }
368
369    #[cfg(test)]
370    mod tests {
371        use super::*;
372
373        #[test]
374        fn test_icmp_type() {
375            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
376            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
377            packet.set_icmp_type(IcmpType::EchoRequest);
378            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
379            assert_eq!([0x08], packet.packet()[0..1]);
380            packet.set_icmp_type(IcmpType::EchoReply);
381            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
382            assert_eq!([0x00], packet.packet()[0..1]);
383            packet.set_icmp_type(IcmpType::DestinationUnreachable);
384            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
385            assert_eq!([0x03], packet.packet()[0..1]);
386            packet.set_icmp_type(IcmpType::TimeExceeded);
387            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
388            assert_eq!([0x0B], packet.packet()[0..1]);
389            packet.set_icmp_type(IcmpType::Other(255));
390            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
391            assert_eq!([0xFF], packet.packet()[0..1]);
392        }
393
394        #[test]
395        fn test_icmp_code() {
396            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
397            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
398            packet.set_icmp_code(IcmpCode(0));
399            assert_eq!(IcmpCode(0), packet.get_icmp_code());
400            assert_eq!([0x00], packet.packet()[1..2]);
401            packet.set_icmp_code(IcmpCode(5));
402            assert_eq!(IcmpCode(5), packet.get_icmp_code());
403            assert_eq!([0x05], packet.packet()[1..2]);
404            packet.set_icmp_code(IcmpCode(255));
405            assert_eq!(IcmpCode(255), packet.get_icmp_code());
406            assert_eq!([0xFF], packet.packet()[1..2]);
407        }
408
409        #[test]
410        fn test_checksum() {
411            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
412            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
413            packet.set_checksum(0);
414            assert_eq!(0, packet.get_checksum());
415            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
416            packet.set_checksum(1999);
417            assert_eq!(1999, packet.get_checksum());
418            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
419            packet.set_checksum(u16::MAX);
420            assert_eq!(u16::MAX, packet.get_checksum());
421            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
422        }
423
424        #[test]
425        fn test_identifier() {
426            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
427            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
428            packet.set_identifier(0);
429            assert_eq!(0, packet.get_identifier());
430            assert_eq!([0x00, 0x00], packet.packet()[4..=5]);
431            packet.set_identifier(1999);
432            assert_eq!(1999, packet.get_identifier());
433            assert_eq!([0x07, 0xCF], packet.packet()[4..=5]);
434            packet.set_identifier(u16::MAX);
435            assert_eq!(u16::MAX, packet.get_identifier());
436            assert_eq!([0xFF, 0xFF], packet.packet()[4..=5]);
437        }
438
439        #[test]
440        fn test_sequence() {
441            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
442            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
443            packet.set_sequence(0);
444            assert_eq!(0, packet.get_sequence());
445            assert_eq!([0x00, 0x00], packet.packet()[6..=7]);
446            packet.set_sequence(1999);
447            assert_eq!(1999, packet.get_sequence());
448            assert_eq!([0x07, 0xCF], packet.packet()[6..=7]);
449            packet.set_sequence(u16::MAX);
450            assert_eq!(u16::MAX, packet.get_sequence());
451            assert_eq!([0xFF, 0xFF], packet.packet()[6..=7]);
452        }
453
454        #[test]
455        fn test_view() {
456            let buf = [0x08, 0x00, 0x16, 0x7c, 0x60, 0x9b, 0x82, 0x9a];
457            let packet = EchoRequestPacket::new_view(&buf).unwrap();
458            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
459            assert_eq!(IcmpCode(0), packet.get_icmp_code());
460            assert_eq!(5756, packet.get_checksum());
461            assert_eq!(24731, packet.get_identifier());
462            assert_eq!(33434, packet.get_sequence());
463            assert!(packet.payload().is_empty());
464        }
465
466        #[test]
467        fn test_new_insufficient_buffer() {
468            const SIZE: usize = EchoRequestPacket::minimum_packet_size();
469            let mut buf = [0_u8; SIZE - 1];
470            let err = EchoRequestPacket::new(&mut buf).unwrap_err();
471            assert_eq!(
472                Error::InsufficientPacketBuffer(String::from("EchoRequestPacket"), SIZE, SIZE - 1),
473                err
474            );
475        }
476
477        #[test]
478        fn test_new_view_insufficient_buffer() {
479            const SIZE: usize = EchoRequestPacket::minimum_packet_size();
480            let buf = [0_u8; SIZE - 1];
481            let err = EchoRequestPacket::new_view(&buf).unwrap_err();
482            assert_eq!(
483                Error::InsufficientPacketBuffer(String::from("EchoRequestPacket"), SIZE, SIZE - 1),
484                err
485            );
486        }
487    }
488}
489
490pub mod echo_reply {
491    use crate::buffer::Buffer;
492    use crate::error::{Error, Result};
493    use crate::fmt_payload;
494    use crate::icmpv4::{IcmpCode, IcmpType};
495    use std::fmt::{Debug, Formatter};
496
497    const TYPE_OFFSET: usize = 0;
498    const CODE_OFFSET: usize = 1;
499    const CHECKSUM_OFFSET: usize = 2;
500    const IDENTIFIER_OFFSET: usize = 4;
501    const SEQUENCE_OFFSET: usize = 6;
502
503    /// Represents an ICMP `EchoReply` packet.
504    ///
505    /// The internal representation is held in network byte order (big-endian) and all accessor
506    /// methods take and return data in host byte order, converting as necessary for the given
507    /// architecture.
508    pub struct EchoReplyPacket<'a> {
509        buf: Buffer<'a>,
510    }
511
512    impl<'a> EchoReplyPacket<'a> {
513        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
514            if packet.len() >= Self::minimum_packet_size() {
515                Ok(Self {
516                    buf: Buffer::Mutable(packet),
517                })
518            } else {
519                Err(Error::InsufficientPacketBuffer(
520                    String::from("EchoReplyPacket"),
521                    Self::minimum_packet_size(),
522                    packet.len(),
523                ))
524            }
525        }
526
527        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
528            if packet.len() >= Self::minimum_packet_size() {
529                Ok(Self {
530                    buf: Buffer::Immutable(packet),
531                })
532            } else {
533                Err(Error::InsufficientPacketBuffer(
534                    String::from("EchoReplyPacket"),
535                    Self::minimum_packet_size(),
536                    packet.len(),
537                ))
538            }
539        }
540
541        #[must_use]
542        pub const fn minimum_packet_size() -> usize {
543            8
544        }
545
546        #[must_use]
547        pub fn get_icmp_type(&self) -> IcmpType {
548            IcmpType::from(self.buf.read(TYPE_OFFSET))
549        }
550
551        #[must_use]
552        pub fn get_icmp_code(&self) -> IcmpCode {
553            IcmpCode::from(self.buf.read(CODE_OFFSET))
554        }
555
556        #[must_use]
557        pub fn get_checksum(&self) -> u16 {
558            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
559        }
560
561        #[must_use]
562        pub fn get_identifier(&self) -> u16 {
563            u16::from_be_bytes(self.buf.get_bytes(IDENTIFIER_OFFSET))
564        }
565
566        #[must_use]
567        pub fn get_sequence(&self) -> u16 {
568            u16::from_be_bytes(self.buf.get_bytes(SEQUENCE_OFFSET))
569        }
570
571        pub fn set_icmp_type(&mut self, val: IcmpType) {
572            *self.buf.write(TYPE_OFFSET) = val.id();
573        }
574
575        pub fn set_icmp_code(&mut self, val: IcmpCode) {
576            *self.buf.write(CODE_OFFSET) = val.0;
577        }
578
579        pub fn set_checksum(&mut self, val: u16) {
580            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
581        }
582
583        pub fn set_identifier(&mut self, val: u16) {
584            self.buf.set_bytes(IDENTIFIER_OFFSET, val.to_be_bytes());
585        }
586
587        pub fn set_sequence(&mut self, val: u16) {
588            self.buf.set_bytes(SEQUENCE_OFFSET, val.to_be_bytes());
589        }
590
591        pub fn set_payload(&mut self, vals: &[u8]) {
592            let current_offset = Self::minimum_packet_size();
593            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
594                .copy_from_slice(vals);
595        }
596
597        #[must_use]
598        pub fn packet(&self) -> &[u8] {
599            self.buf.as_slice()
600        }
601
602        #[must_use]
603        pub fn payload(&self) -> &[u8] {
604            &self.buf.as_slice()[Self::minimum_packet_size()..]
605        }
606    }
607
608    impl Debug for EchoReplyPacket<'_> {
609        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
610            f.debug_struct("EchoReplyPacket")
611                .field("icmp_type", &self.get_icmp_type())
612                .field("icmp_code", &self.get_icmp_code())
613                .field("checksum", &self.get_checksum())
614                .field("identifier", &self.get_identifier())
615                .field("sequence", &self.get_sequence())
616                .field("payload", &fmt_payload(self.payload()))
617                .finish()
618        }
619    }
620
621    #[cfg(test)]
622    mod tests {
623        use super::*;
624
625        #[test]
626        fn test_icmp_type() {
627            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
628            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
629            packet.set_icmp_type(IcmpType::EchoRequest);
630            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
631            assert_eq!([0x08], packet.packet()[0..1]);
632            packet.set_icmp_type(IcmpType::EchoReply);
633            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
634            assert_eq!([0x00], packet.packet()[0..1]);
635            packet.set_icmp_type(IcmpType::DestinationUnreachable);
636            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
637            assert_eq!([0x03], packet.packet()[0..1]);
638            packet.set_icmp_type(IcmpType::TimeExceeded);
639            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
640            assert_eq!([0x0B], packet.packet()[0..1]);
641            packet.set_icmp_type(IcmpType::Other(255));
642            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
643            assert_eq!([0xFF], packet.packet()[0..1]);
644        }
645
646        #[test]
647        fn test_icmp_code() {
648            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
649            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
650            packet.set_icmp_code(IcmpCode(0));
651            assert_eq!(IcmpCode(0), packet.get_icmp_code());
652            assert_eq!([0x00], packet.packet()[1..2]);
653            packet.set_icmp_code(IcmpCode(5));
654            assert_eq!(IcmpCode(5), packet.get_icmp_code());
655            assert_eq!([0x05], packet.packet()[1..2]);
656            packet.set_icmp_code(IcmpCode(255));
657            assert_eq!(IcmpCode(255), packet.get_icmp_code());
658            assert_eq!([0xFF], packet.packet()[1..2]);
659        }
660
661        #[test]
662        fn test_checksum() {
663            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
664            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
665            packet.set_checksum(0);
666            assert_eq!(0, packet.get_checksum());
667            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
668            packet.set_checksum(1999);
669            assert_eq!(1999, packet.get_checksum());
670            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
671            packet.set_checksum(u16::MAX);
672            assert_eq!(u16::MAX, packet.get_checksum());
673            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
674        }
675
676        #[test]
677        fn test_identifier() {
678            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
679            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
680            packet.set_identifier(0);
681            assert_eq!(0, packet.get_identifier());
682            assert_eq!([0x00, 0x00], packet.packet()[4..=5]);
683            packet.set_identifier(1999);
684            assert_eq!(1999, packet.get_identifier());
685            assert_eq!([0x07, 0xCF], packet.packet()[4..=5]);
686            packet.set_identifier(u16::MAX);
687            assert_eq!(u16::MAX, packet.get_identifier());
688            assert_eq!([0xFF, 0xFF], packet.packet()[4..=5]);
689        }
690
691        #[test]
692        fn test_sequence() {
693            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
694            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
695            packet.set_sequence(0);
696            assert_eq!(0, packet.get_sequence());
697            assert_eq!([0x00, 0x00], packet.packet()[6..=7]);
698            packet.set_sequence(1999);
699            assert_eq!(1999, packet.get_sequence());
700            assert_eq!([0x07, 0xCF], packet.packet()[6..=7]);
701            packet.set_sequence(u16::MAX);
702            assert_eq!(u16::MAX, packet.get_sequence());
703            assert_eq!([0xFF, 0xFF], packet.packet()[6..=7]);
704        }
705
706        #[test]
707        fn test_view() {
708            let buf = [0x00, 0x00, 0x1e, 0x70, 0x60, 0x9b, 0x80, 0xf4];
709            let packet = EchoReplyPacket::new_view(&buf).unwrap();
710            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
711            assert_eq!(IcmpCode(0), packet.get_icmp_code());
712            assert_eq!(7792, packet.get_checksum());
713            assert_eq!(24731, packet.get_identifier());
714            assert_eq!(33012, packet.get_sequence());
715            assert!(packet.payload().is_empty());
716        }
717
718        #[test]
719        fn test_new_insufficient_buffer() {
720            const SIZE: usize = EchoReplyPacket::minimum_packet_size();
721            let mut buf = [0_u8; SIZE - 1];
722            let err = EchoReplyPacket::new(&mut buf).unwrap_err();
723            assert_eq!(
724                Error::InsufficientPacketBuffer(String::from("EchoReplyPacket"), SIZE, SIZE - 1),
725                err
726            );
727        }
728
729        #[test]
730        fn test_new_view_insufficient_buffer() {
731            const SIZE: usize = EchoReplyPacket::minimum_packet_size();
732            let buf = [0_u8; SIZE - 1];
733            let err = EchoReplyPacket::new_view(&buf).unwrap_err();
734            assert_eq!(
735                Error::InsufficientPacketBuffer(String::from("EchoReplyPacket"), SIZE, SIZE - 1),
736                err
737            );
738        }
739    }
740}
741
742pub mod time_exceeded {
743    use crate::buffer::Buffer;
744    use crate::error::{Error, Result};
745    use crate::fmt_payload;
746    use crate::icmp_extension::extension_splitter::split;
747    use crate::icmpv4::{IcmpCode, IcmpType};
748    use std::fmt::{Debug, Formatter};
749
750    const TYPE_OFFSET: usize = 0;
751    const CODE_OFFSET: usize = 1;
752    const CHECKSUM_OFFSET: usize = 2;
753    const LENGTH_OFFSET: usize = 5;
754
755    /// Represents an ICMP `TimeExceeded` packet.
756    ///
757    /// The internal representation is held in network byte order (big-endian) and all accessor
758    /// methods take and return data in host byte order, converting as necessary for the given
759    /// architecture.
760    pub struct TimeExceededPacket<'a> {
761        buf: Buffer<'a>,
762    }
763
764    impl<'a> TimeExceededPacket<'a> {
765        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
766            if packet.len() >= Self::minimum_packet_size() {
767                Ok(Self {
768                    buf: Buffer::Mutable(packet),
769                })
770            } else {
771                Err(Error::InsufficientPacketBuffer(
772                    String::from("TimeExceededPacket"),
773                    Self::minimum_packet_size(),
774                    packet.len(),
775                ))
776            }
777        }
778
779        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
780            if packet.len() >= Self::minimum_packet_size() {
781                Ok(Self {
782                    buf: Buffer::Immutable(packet),
783                })
784            } else {
785                Err(Error::InsufficientPacketBuffer(
786                    String::from("TimeExceededPacket"),
787                    Self::minimum_packet_size(),
788                    packet.len(),
789                ))
790            }
791        }
792
793        #[must_use]
794        pub const fn minimum_packet_size() -> usize {
795            8
796        }
797
798        #[must_use]
799        pub fn get_icmp_type(&self) -> IcmpType {
800            IcmpType::from(self.buf.read(TYPE_OFFSET))
801        }
802
803        #[must_use]
804        pub fn get_icmp_code(&self) -> IcmpCode {
805            IcmpCode::from(self.buf.read(CODE_OFFSET))
806        }
807
808        #[must_use]
809        pub fn get_checksum(&self) -> u16 {
810            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
811        }
812
813        #[must_use]
814        pub fn get_length(&self) -> u8 {
815            self.buf.read(LENGTH_OFFSET)
816        }
817
818        pub fn set_icmp_type(&mut self, val: IcmpType) {
819            *self.buf.write(TYPE_OFFSET) = val.id();
820        }
821
822        pub fn set_icmp_code(&mut self, val: IcmpCode) {
823            *self.buf.write(CODE_OFFSET) = val.0;
824        }
825
826        pub fn set_checksum(&mut self, val: u16) {
827            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
828        }
829
830        pub fn set_length(&mut self, val: u8) {
831            *self.buf.write(LENGTH_OFFSET) = val;
832        }
833
834        pub fn set_payload(&mut self, vals: &[u8]) {
835            let current_offset = Self::minimum_packet_size();
836            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
837                .copy_from_slice(vals);
838        }
839
840        #[must_use]
841        pub fn packet(&self) -> &[u8] {
842            self.buf.as_slice()
843        }
844
845        #[must_use]
846        pub fn payload(&self) -> &[u8] {
847            let (payload, _) = self.split_payload_extension();
848            payload
849        }
850
851        #[must_use]
852        pub fn payload_raw(&self) -> &[u8] {
853            &self.buf.as_slice()[Self::minimum_packet_size()..]
854        }
855
856        #[must_use]
857        pub fn extension(&self) -> Option<&[u8]> {
858            let (_, extension) = self.split_payload_extension();
859            extension
860        }
861
862        fn split_payload_extension(&self) -> (&[u8], Option<&[u8]>) {
863            // From rfc4884:
864            //
865            // "For ICMPv4 messages, the length attribute represents 32-bit words
866            let length = usize::from(self.get_length()) * 4;
867            let icmp_payload = &self.buf.as_slice()[Self::minimum_packet_size()..];
868            split(length, icmp_payload)
869        }
870    }
871
872    impl Debug for TimeExceededPacket<'_> {
873        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
874            f.debug_struct("TimeExceededPacket")
875                .field("icmp_type", &self.get_icmp_type())
876                .field("icmp_code", &self.get_icmp_code())
877                .field("checksum", &self.get_checksum())
878                .field("length", &self.get_length())
879                .field("payload", &fmt_payload(self.payload()))
880                .finish()
881        }
882    }
883
884    #[cfg(test)]
885    mod tests {
886        use super::*;
887
888        #[test]
889        fn test_icmp_type() {
890            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
891            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
892            packet.set_icmp_type(IcmpType::EchoRequest);
893            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
894            assert_eq!([0x08], packet.packet()[0..1]);
895            packet.set_icmp_type(IcmpType::EchoReply);
896            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
897            assert_eq!([0x00], packet.packet()[0..1]);
898            packet.set_icmp_type(IcmpType::DestinationUnreachable);
899            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
900            assert_eq!([0x03], packet.packet()[0..1]);
901            packet.set_icmp_type(IcmpType::TimeExceeded);
902            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
903            assert_eq!([0x0B], packet.packet()[0..1]);
904            packet.set_icmp_type(IcmpType::Other(255));
905            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
906            assert_eq!([0xFF], packet.packet()[0..1]);
907        }
908
909        #[test]
910        fn test_icmp_code() {
911            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
912            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
913            packet.set_icmp_code(IcmpCode(0));
914            assert_eq!(IcmpCode(0), packet.get_icmp_code());
915            assert_eq!([0x00], packet.packet()[1..2]);
916            packet.set_icmp_code(IcmpCode(5));
917            assert_eq!(IcmpCode(5), packet.get_icmp_code());
918            assert_eq!([0x05], packet.packet()[1..2]);
919            packet.set_icmp_code(IcmpCode(255));
920            assert_eq!(IcmpCode(255), packet.get_icmp_code());
921            assert_eq!([0xFF], packet.packet()[1..2]);
922        }
923
924        #[test]
925        fn test_checksum() {
926            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
927            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
928            packet.set_checksum(0);
929            assert_eq!(0, packet.get_checksum());
930            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
931            packet.set_checksum(1999);
932            assert_eq!(1999, packet.get_checksum());
933            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
934            packet.set_checksum(u16::MAX);
935            assert_eq!(u16::MAX, packet.get_checksum());
936            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
937        }
938
939        #[test]
940        fn test_length() {
941            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
942            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
943            packet.set_length(0);
944            assert_eq!(0, packet.get_length());
945            assert_eq!([0x00], packet.packet()[5..6]);
946            packet.set_length(8);
947            assert_eq!(8, packet.get_length());
948            assert_eq!([0x08], packet.packet()[5..6]);
949            packet.set_length(u8::MAX);
950            assert_eq!(u8::MAX, packet.get_length());
951            assert_eq!([0xFF], packet.packet()[5..6]);
952        }
953
954        #[test]
955        fn test_view() {
956            let buf = [0x0b, 0x00, 0xf4, 0xee, 0x00, 0x11, 0x00, 0x00];
957            let packet = TimeExceededPacket::new_view(&buf).unwrap();
958            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
959            assert_eq!(IcmpCode(0), packet.get_icmp_code());
960            assert_eq!(62702, packet.get_checksum());
961            assert_eq!(17, packet.get_length());
962            assert!(packet.payload().is_empty());
963        }
964
965        #[test]
966        fn test_view_large() {
967            let mut buf = [0x0_u8; 256];
968            buf[..8].copy_from_slice(&[0x0b, 0x00, 0xf4, 0xee, 0x00, 0x40, 0x00, 0x00]);
969            let packet = TimeExceededPacket::new_view(&buf).unwrap();
970            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
971            assert_eq!(IcmpCode(0), packet.get_icmp_code());
972            assert_eq!(62702, packet.get_checksum());
973            assert_eq!(64, packet.get_length());
974            assert_eq!(&[0x0_u8; 248], packet.payload());
975            assert_eq!(None, packet.extension());
976        }
977
978        #[test]
979        fn test_new_insufficient_buffer() {
980            const SIZE: usize = TimeExceededPacket::minimum_packet_size();
981            let mut buf = [0_u8; SIZE - 1];
982            let err = TimeExceededPacket::new(&mut buf).unwrap_err();
983            assert_eq!(
984                Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
985                err
986            );
987        }
988
989        #[test]
990        fn test_new_view_insufficient_buffer() {
991            const SIZE: usize = TimeExceededPacket::minimum_packet_size();
992            let buf = [0_u8; SIZE - 1];
993            let err = TimeExceededPacket::new_view(&buf).unwrap_err();
994            assert_eq!(
995                Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
996                err
997            );
998        }
999    }
1000}
1001
1002pub mod destination_unreachable {
1003    use crate::buffer::Buffer;
1004    use crate::error::{Error, Result};
1005    use crate::fmt_payload;
1006    use crate::icmp_extension::extension_splitter::split;
1007    use crate::icmpv4::{IcmpCode, IcmpType};
1008    use std::fmt::{Debug, Formatter};
1009
1010    const TYPE_OFFSET: usize = 0;
1011    const CODE_OFFSET: usize = 1;
1012    const CHECKSUM_OFFSET: usize = 2;
1013    const LENGTH_OFFSET: usize = 5;
1014    const NEXT_HOP_MTU_OFFSET: usize = 6;
1015
1016    /// Represents an ICMP `DestinationUnreachable` packet.
1017    ///
1018    /// The internal representation is held in network byte order (big-endian) and all accessor
1019    /// methods take and return data in host byte order, converting as necessary for the given
1020    /// architecture.
1021    pub struct DestinationUnreachablePacket<'a> {
1022        buf: Buffer<'a>,
1023    }
1024
1025    impl<'a> DestinationUnreachablePacket<'a> {
1026        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
1027            if packet.len() >= Self::minimum_packet_size() {
1028                Ok(Self {
1029                    buf: Buffer::Mutable(packet),
1030                })
1031            } else {
1032                Err(Error::InsufficientPacketBuffer(
1033                    String::from("DestinationUnreachablePacket"),
1034                    Self::minimum_packet_size(),
1035                    packet.len(),
1036                ))
1037            }
1038        }
1039
1040        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
1041            if packet.len() >= Self::minimum_packet_size() {
1042                Ok(Self {
1043                    buf: Buffer::Immutable(packet),
1044                })
1045            } else {
1046                Err(Error::InsufficientPacketBuffer(
1047                    String::from("DestinationUnreachablePacket"),
1048                    Self::minimum_packet_size(),
1049                    packet.len(),
1050                ))
1051            }
1052        }
1053
1054        #[must_use]
1055        pub const fn minimum_packet_size() -> usize {
1056            8
1057        }
1058
1059        #[must_use]
1060        pub fn get_icmp_type(&self) -> IcmpType {
1061            IcmpType::from(self.buf.read(TYPE_OFFSET))
1062        }
1063
1064        #[must_use]
1065        pub fn get_icmp_code(&self) -> IcmpCode {
1066            IcmpCode::from(self.buf.read(CODE_OFFSET))
1067        }
1068
1069        #[must_use]
1070        pub fn get_checksum(&self) -> u16 {
1071            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
1072        }
1073
1074        #[must_use]
1075        pub fn get_length(&self) -> u8 {
1076            self.buf.read(LENGTH_OFFSET)
1077        }
1078
1079        #[must_use]
1080        pub fn get_next_hop_mtu(&self) -> u16 {
1081            u16::from_be_bytes(self.buf.get_bytes(NEXT_HOP_MTU_OFFSET))
1082        }
1083
1084        pub fn set_icmp_type(&mut self, val: IcmpType) {
1085            *self.buf.write(TYPE_OFFSET) = val.id();
1086        }
1087
1088        pub fn set_icmp_code(&mut self, val: IcmpCode) {
1089            *self.buf.write(CODE_OFFSET) = val.0;
1090        }
1091
1092        pub fn set_checksum(&mut self, val: u16) {
1093            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
1094        }
1095
1096        pub fn set_length(&mut self, val: u8) {
1097            *self.buf.write(LENGTH_OFFSET) = val;
1098        }
1099
1100        pub fn set_next_hop_mtu(&mut self, val: u16) {
1101            self.buf.set_bytes(NEXT_HOP_MTU_OFFSET, val.to_be_bytes());
1102        }
1103
1104        pub fn set_payload(&mut self, vals: &[u8]) {
1105            let current_offset = Self::minimum_packet_size();
1106            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
1107                .copy_from_slice(vals);
1108        }
1109
1110        #[must_use]
1111        pub fn packet(&self) -> &[u8] {
1112            self.buf.as_slice()
1113        }
1114
1115        #[must_use]
1116        pub fn payload(&self) -> &[u8] {
1117            let (payload, _) = self.split_payload_extension();
1118            payload
1119        }
1120
1121        #[must_use]
1122        pub fn payload_raw(&self) -> &[u8] {
1123            &self.buf.as_slice()[Self::minimum_packet_size()..]
1124        }
1125
1126        #[must_use]
1127        pub fn extension(&self) -> Option<&[u8]> {
1128            let (_, extension) = self.split_payload_extension();
1129            extension
1130        }
1131
1132        fn split_payload_extension(&self) -> (&[u8], Option<&[u8]>) {
1133            let length = usize::from(self.get_length()) * 4;
1134            let icmp_payload = &self.buf.as_slice()[Self::minimum_packet_size()..];
1135            split(length, icmp_payload)
1136        }
1137    }
1138
1139    impl Debug for DestinationUnreachablePacket<'_> {
1140        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1141            f.debug_struct("DestinationUnreachablePacket")
1142                .field("icmp_type", &self.get_icmp_type())
1143                .field("icmp_code", &self.get_icmp_code())
1144                .field("checksum", &self.get_checksum())
1145                .field("length", &self.get_length())
1146                .field("next_hop_mtu", &self.get_next_hop_mtu())
1147                .field("payload", &fmt_payload(self.payload()))
1148                .finish()
1149        }
1150    }
1151
1152    #[cfg(test)]
1153    mod tests {
1154        use super::*;
1155
1156        #[test]
1157        fn test_icmp_type() {
1158            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1159            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1160            packet.set_icmp_type(IcmpType::EchoRequest);
1161            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
1162            assert_eq!([0x08], packet.packet()[0..1]);
1163            packet.set_icmp_type(IcmpType::EchoReply);
1164            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
1165            assert_eq!([0x00], packet.packet()[0..1]);
1166            packet.set_icmp_type(IcmpType::DestinationUnreachable);
1167            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1168            assert_eq!([0x03], packet.packet()[0..1]);
1169            packet.set_icmp_type(IcmpType::TimeExceeded);
1170            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
1171            assert_eq!([0x0B], packet.packet()[0..1]);
1172            packet.set_icmp_type(IcmpType::Other(255));
1173            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
1174            assert_eq!([0xFF], packet.packet()[0..1]);
1175        }
1176
1177        #[test]
1178        fn test_icmp_code() {
1179            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1180            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1181            packet.set_icmp_code(IcmpCode(0));
1182            assert_eq!(IcmpCode(0), packet.get_icmp_code());
1183            assert_eq!([0x00], packet.packet()[1..2]);
1184            packet.set_icmp_code(IcmpCode(5));
1185            assert_eq!(IcmpCode(5), packet.get_icmp_code());
1186            assert_eq!([0x05], packet.packet()[1..2]);
1187            packet.set_icmp_code(IcmpCode(255));
1188            assert_eq!(IcmpCode(255), packet.get_icmp_code());
1189            assert_eq!([0xFF], packet.packet()[1..2]);
1190        }
1191
1192        #[test]
1193        fn test_checksum() {
1194            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1195            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1196            packet.set_checksum(0);
1197            assert_eq!(0, packet.get_checksum());
1198            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
1199            packet.set_checksum(1999);
1200            assert_eq!(1999, packet.get_checksum());
1201            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
1202            packet.set_checksum(u16::MAX);
1203            assert_eq!(u16::MAX, packet.get_checksum());
1204            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
1205        }
1206
1207        #[test]
1208        fn test_length() {
1209            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1210            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1211            packet.set_length(0);
1212            assert_eq!(0, packet.get_length());
1213            assert_eq!([0x00], packet.packet()[5..6]);
1214            packet.set_length(8);
1215            assert_eq!(8, packet.get_length());
1216            assert_eq!([0x08], packet.packet()[5..6]);
1217            packet.set_length(u8::MAX);
1218            assert_eq!(u8::MAX, packet.get_length());
1219            assert_eq!([0xFF], packet.packet()[5..6]);
1220        }
1221
1222        #[test]
1223        fn test_view() {
1224            let buf = [0x03, 0x03, 0xdf, 0xdc, 0x00, 0x00, 0x00, 0x00];
1225            let packet = DestinationUnreachablePacket::new_view(&buf).unwrap();
1226            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1227            assert_eq!(IcmpCode(3), packet.get_icmp_code());
1228            assert_eq!(57308, packet.get_checksum());
1229            assert_eq!(0, packet.get_length());
1230            assert!(packet.payload().is_empty());
1231        }
1232
1233        #[test]
1234        fn test_view_large() {
1235            let mut buf = [0x0_u8; 256];
1236            buf[..8].copy_from_slice(&[0x03, 0x03, 0xdf, 0xdc, 0x00, 0x40, 0x00, 0x00]);
1237            let packet = DestinationUnreachablePacket::new_view(&buf).unwrap();
1238            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1239            assert_eq!(IcmpCode(3), packet.get_icmp_code());
1240            assert_eq!(57308, packet.get_checksum());
1241            assert_eq!(64, packet.get_length());
1242            assert_eq!(&[0x0_u8; 248], packet.payload());
1243            assert_eq!(None, packet.extension());
1244        }
1245
1246        #[test]
1247        fn test_new_insufficient_buffer() {
1248            const SIZE: usize = DestinationUnreachablePacket::minimum_packet_size();
1249            let mut buf = [0_u8; SIZE - 1];
1250            let err = DestinationUnreachablePacket::new(&mut buf).unwrap_err();
1251            assert_eq!(
1252                Error::InsufficientPacketBuffer(
1253                    String::from("DestinationUnreachablePacket"),
1254                    SIZE,
1255                    SIZE - 1
1256                ),
1257                err
1258            );
1259        }
1260
1261        #[test]
1262        fn test_new_view_insufficient_buffer() {
1263            const SIZE: usize = DestinationUnreachablePacket::minimum_packet_size();
1264            let buf = [0_u8; SIZE - 1];
1265            let err = DestinationUnreachablePacket::new_view(&buf).unwrap_err();
1266            assert_eq!(
1267                Error::InsufficientPacketBuffer(
1268                    String::from("DestinationUnreachablePacket"),
1269                    SIZE,
1270                    SIZE - 1
1271                ),
1272                err
1273            );
1274        }
1275    }
1276}