async_icmp/message/
decode.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//! Support for decoding ICMP packets.

use winnow::{binary, combinator, Parser as _};

/// A generic decoded ICMP message.
///
/// Further type-specific decoding should be done on the contents.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecodedIcmpMsg<'a> {
    msg_type: u8,
    msg_code: u8,
    checksum: u16,
    body: &'a [u8],
}

impl<'a> DecodedIcmpMsg<'a> {
    /// Decode an ICMP msg, if `input` is valid.
    pub fn decode(input: &'a [u8]) -> Result<Self, InvalidIcmpMsg> {
        (
            binary::u8::<_, winnow::error::ContextError>,
            binary::u8,
            binary::be_u16,
            combinator::rest,
        )
            .map(|(msg_type, msg_code, checksum, contents)| Self {
                msg_type,
                msg_code,
                checksum,
                body: contents,
            })
            .parse(input)
            .map_err(|_| InvalidIcmpMsg)
    }

    /// ICMP message type
    pub fn msg_type(&self) -> u8 {
        self.msg_type
    }

    /// ICMP message code
    pub fn msg_code(&self) -> u8 {
        self.msg_code
    }

    /// Checksum
    pub fn checksum(&self) -> u16 {
        self.checksum
    }

    /// Message body (everything after the checksum).
    ///
    /// Interpretation of the body varies by the message type.
    pub fn body(&self) -> &[u8] {
        self.body
    }
}

/// Error used when decoding an ICMP message fails.
#[derive(Debug, thiserror::Error)]
#[error("Input is not a valid ICMP message")]
pub struct InvalidIcmpMsg;