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);