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