async_icmp/message/
decode.rs

1//! Support for decoding ICMP packets.
2
3use winnow::{binary, combinator, Parser as _};
4
5/// A generic decoded ICMP message.
6///
7/// Further type-specific decoding should be done on the contents.
8#[derive(Debug, PartialEq, Eq, Clone)]
9pub struct DecodedIcmpMsg<'a> {
10    msg_type: u8,
11    msg_code: u8,
12    checksum: u16,
13    body: &'a [u8],
14}
15
16impl<'a> DecodedIcmpMsg<'a> {
17    /// Decode an ICMP msg, if `input` is valid.
18    pub fn decode(input: &'a [u8]) -> Result<Self, InvalidIcmpMsg> {
19        (
20            binary::u8::<_, winnow::error::ContextError>,
21            binary::u8,
22            binary::be_u16,
23            combinator::rest,
24        )
25            .map(|(msg_type, msg_code, checksum, contents)| Self {
26                msg_type,
27                msg_code,
28                checksum,
29                body: contents,
30            })
31            .parse(input)
32            .map_err(|_| InvalidIcmpMsg)
33    }
34
35    /// ICMP message type
36    pub fn msg_type(&self) -> u8 {
37        self.msg_type
38    }
39
40    /// ICMP message code
41    pub fn msg_code(&self) -> u8 {
42        self.msg_code
43    }
44
45    /// Checksum
46    pub fn checksum(&self) -> u16 {
47        self.checksum
48    }
49
50    /// Message body (everything after the checksum).
51    ///
52    /// Interpretation of the body varies by the message type.
53    pub fn body(&self) -> &[u8] {
54        self.body
55    }
56}
57
58/// Error used when decoding an ICMP message fails.
59#[derive(Debug, thiserror::Error)]
60#[error("Input is not a valid ICMP message")]
61pub struct InvalidIcmpMsg;