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