packet_formats/
error.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Custom error types for the packet formats.
6
7use core::convert::Infallible as Never;
8
9use net_types::ip::IpAddress;
10use net_types::MulticastAddress;
11use packet::records::options::OptionParseErr;
12use packet::records::TooFewRecordsErr;
13use thiserror::Error;
14
15use crate::icmp::IcmpIpExt;
16
17/// Results returned from parsing functions in the netstack.
18pub type ParseResult<T> = core::result::Result<T, ParseError>;
19
20/// Results returned from IP packet parsing functions in the netstack.
21pub type IpParseResult<I, T> = core::result::Result<T, IpParseError<I>>;
22
23/// Error type for packet parsing.
24#[derive(Copy, Clone, Error, Debug, PartialEq)]
25pub enum ParseError {
26    /// Operation is not supported.
27    #[error("Operation is not supported")]
28    NotSupported,
29    /// Operation is not expected in this context.
30    #[error("Operation is not expected in this context")]
31    NotExpected,
32    /// Checksum is invalid.
33    #[error("Invalid checksum")]
34    Checksum,
35    /// Packet is not formatted properly.
36    #[error("Packet is not formatted properly")]
37    Format,
38}
39
40impl From<Never> for ParseError {
41    fn from(err: Never) -> ParseError {
42        match err {}
43    }
44}
45
46impl From<TooFewRecordsErr> for ParseError {
47    fn from(TooFewRecordsErr: TooFewRecordsErr) -> ParseError {
48        ParseError::Format
49    }
50}
51
52impl From<OptionParseErr> for ParseError {
53    fn from(OptionParseErr: OptionParseErr) -> ParseError {
54        ParseError::Format
55    }
56}
57
58/// Action to take when an IP node fails to parse a received IP packet.
59///
60/// These actions are taken from [RFC 8200 section 4.2]. Although these actions
61/// are defined by an IPv6 RFC, IPv4 nodes that fail to parse a received packet
62/// will take similar actions.
63///
64/// [RFC 8200 section 4.2]: https://tools.ietf.org/html/rfc8200#section-4.2
65#[derive(Copy, Clone, Debug, PartialEq)]
66pub enum IpParseErrorAction {
67    /// Discard the packet and do nothing further.
68    DiscardPacket,
69
70    /// Discard the packet and send an ICMP response.
71    DiscardPacketSendIcmp,
72
73    /// Discard the packet and send an ICMP response if the packet's
74    /// destination address was not a multicast address.
75    DiscardPacketSendIcmpNoMulticast,
76}
77
78impl IpParseErrorAction {
79    /// Determines whether or not an ICMP message should be sent.
80    ///
81    /// Returns `true` if the caller should send an ICMP response. The caller should
82    /// send an ICMP response if an action is set to `DiscardPacketSendIcmp`, or
83    /// if an action is set to `DiscardPacketSendIcmpNoMulticast` and `dst_addr`
84    /// (the destination address of the original packet that lead to a parsing
85    /// error) is not a multicast address.
86    pub fn should_send_icmp<A: IpAddress>(&self, dst_addr: &A) -> bool {
87        match *self {
88            IpParseErrorAction::DiscardPacket => false,
89            IpParseErrorAction::DiscardPacketSendIcmp => true,
90            IpParseErrorAction::DiscardPacketSendIcmpNoMulticast => !dst_addr.is_multicast(),
91        }
92    }
93
94    /// Determines whether or not an ICMP message should be sent even if the original
95    /// packet's destination address is a multicast.
96    ///
97    /// Per [RFC 1122 section 3.2.2] and [RFC 4443 section 2.4], ICMP messages MUST NOT
98    /// be sent in response to packets destined to a multicast or broadcast address.
99    /// However, RFC 4443 section 2.4 includes an exception to this rule if certain
100    /// criteria are met when parsing IPv6 extension header options.
101    /// `should_send_icmp_to_multicast` returns `true` if the criteria are met.
102    /// See RFC 4443 section 2.4 for more details about the exception.
103    ///
104    /// [RFC 1122 section 3.2.2]: https://tools.ietf.org/html/rfc1122#section-3.2.2
105    /// [RFC 4443 section 2.4]: https://tools.ietf.org/html/rfc4443#section-2.4
106    pub fn should_send_icmp_to_multicast(&self) -> bool {
107        match *self {
108            IpParseErrorAction::DiscardPacketSendIcmp => true,
109            IpParseErrorAction::DiscardPacket
110            | IpParseErrorAction::DiscardPacketSendIcmpNoMulticast => false,
111        }
112    }
113}
114
115/// Error type for IP packet parsing.
116#[allow(missing_docs)]
117#[derive(Error, Debug, PartialEq)]
118pub enum IpParseError<I: IcmpIpExt> {
119    #[error("Parsing Error: {error:?}")]
120    Parse {
121        #[from]
122        error: ParseError,
123    },
124    /// For errors where an ICMP Parameter Problem error needs to be sent to the
125    /// source of a packet.
126    #[error("Parameter Problem")]
127    ParameterProblem {
128        /// The packet's source IP address.
129        src_ip: I::Addr,
130
131        /// The packet's destination IP address.
132        dst_ip: I::Addr,
133
134        /// The ICMPv4 or ICMPv6 parameter problem code that provides more
135        /// granular information about the parameter problem encountered.
136        code: I::ParameterProblemCode,
137
138        /// The offset of the erroneous value within the IP packet.
139        pointer: I::ParameterProblemPointer,
140
141        /// Whether an IP node MUST send an ICMP response if [`action`]
142        /// specifies it.
143        ///
144        /// See [`action`] for more details.
145        ///
146        /// [`action`]: crate::error::IpParseError::ParameterProblem::action
147        must_send_icmp: bool,
148
149        /// The length of the header up to the point of the parameter problem
150        /// error.
151        header_len: I::HeaderLen,
152
153        /// The action IP nodes should take upon encountering this error.
154        ///
155        /// If [`must_send_icmp`] is `true`, IP nodes MUST send an ICMP response
156        /// if `action` specifies it. Otherwise, the node MAY choose to discard
157        /// the packet and do nothing further.
158        ///
159        /// If the packet was an IPv4 non-initial fragment, `action` will be
160        /// [`IpParseErrorAction::DiscardPacket`].
161        ///
162        /// [`must_send_icmp`]: crate::error::IpParseError::ParameterProblem::must_send_icmp
163        action: IpParseErrorAction,
164    },
165}
166
167impl<I: IcmpIpExt> From<OptionParseErr> for IpParseError<I> {
168    fn from(error: OptionParseErr) -> Self {
169        IpParseError::Parse { error: error.into() }
170    }
171}
172
173/// Error type for an unrecognized protocol code of type `T`.
174#[derive(Debug, Eq, PartialEq)]
175pub struct UnrecognizedProtocolCode<T>(pub T);
176
177/// A not zero value for `T` was observed, but zero was expected.
178#[derive(Debug, Eq, PartialEq)]
179pub struct NotZeroError<T>(pub T);