Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion etherparse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ rust-version = "1.83.0"

[features]
default = ["std"]
std = ["arrayvec/std"]
alloc = []
std = ["alloc", "arrayvec/std"]

[dependencies]
arrayvec = { version = "0.7.2", default-features = false }
Expand Down
110 changes: 110 additions & 0 deletions etherparse/src/err/packet/build_slice_write_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use crate::err::{ipv4_exts, ipv6_exts, SliceWriteSpaceError, ValueTooBigError};

/// Error while serializing a packet into a byte slice.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum BuildSliceWriteError {
/// Not enough space is available in the target slice.
/// Contains the minimum required length.
Space(usize),

/// Error if the length of the payload is too
/// big to be representable by the length fields.
PayloadLen(ValueTooBigError<usize>),

/// Error if the IPv4 extensions can not be serialized
/// because of internal consistency errors (i.e. a header
/// is never).
Ipv4Exts(ipv4_exts::ExtsWalkError),

/// Error if the IPv6 extensions can not be serialized
/// because of internal consistency errors.
Ipv6Exts(ipv6_exts::ExtsWalkError),

/// Error if ICMPv6 is packaged in an IPv4 packet (it is undefined
/// how to calculate the checksum).
Icmpv6InIpv4,

/// Address size defined in the ARP header does not match the actual size.
ArpHeaderNotMatch,
}

impl From<ValueTooBigError<usize>> for BuildSliceWriteError {
fn from(value: ValueTooBigError<usize>) -> Self {
BuildSliceWriteError::PayloadLen(value)
}
}

impl From<SliceWriteSpaceError> for BuildSliceWriteError {
fn from(value: SliceWriteSpaceError) -> Self {
BuildSliceWriteError::Space(value.required_len)
}
}

impl From<super::TransportChecksumError> for BuildSliceWriteError {
fn from(value: super::TransportChecksumError) -> Self {
match value {
super::TransportChecksumError::PayloadLen(err) => BuildSliceWriteError::PayloadLen(err),
super::TransportChecksumError::Icmpv6InIpv4 => BuildSliceWriteError::Icmpv6InIpv4,
}
}
}

impl From<crate::WriteError<SliceWriteSpaceError, ipv4_exts::ExtsWalkError>>
for BuildSliceWriteError
{
fn from(value: crate::WriteError<SliceWriteSpaceError, ipv4_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => BuildSliceWriteError::Space(err.required_len),
crate::WriteError::Content(err) => BuildSliceWriteError::Ipv4Exts(err),
}
}
}

impl From<crate::WriteError<SliceWriteSpaceError, ipv6_exts::ExtsWalkError>>
for BuildSliceWriteError
{
fn from(value: crate::WriteError<SliceWriteSpaceError, ipv6_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => BuildSliceWriteError::Space(err.required_len),
crate::WriteError::Content(err) => BuildSliceWriteError::Ipv6Exts(err),
}
}
}

impl core::fmt::Display for BuildSliceWriteError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use BuildSliceWriteError::*;
match self {
Space(required_len) => write!(
f,
"Not enough space to write packet to slice. Needed {} byte(s).",
required_len
),
PayloadLen(err) => err.fmt(f),
Ipv4Exts(err) => err.fmt(f),
Ipv6Exts(err) => err.fmt(f),
ArpHeaderNotMatch => write!(
f,
"address size defined in the ARP header does not match the actual size"
),
Icmpv6InIpv4 => write!(
f,
"Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."
),
}
}
}

impl core::error::Error for BuildSliceWriteError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
use BuildSliceWriteError::*;
match self {
Space(_) => None,
PayloadLen(err) => Some(err),
Ipv4Exts(err) => Some(err),
Ipv6Exts(err) => Some(err),
Icmpv6InIpv4 => None,
ArpHeaderNotMatch => None,
}
}
}
97 changes: 97 additions & 0 deletions etherparse/src/err/packet/build_vec_write_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use crate::err::{ipv4_exts, ipv6_exts, ValueTooBigError};
use core::convert::Infallible;

/// Error while serializing a packet into a [`alloc::vec::Vec`].
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum BuildVecWriteError {
/// Error if the length of the payload is too
/// big to be representable by the length fields.
PayloadLen(ValueTooBigError<usize>),

/// Error if the IPv4 extensions can not be serialized
/// because of internal consistency errors (i.e. a header
/// is never).
Ipv4Exts(ipv4_exts::ExtsWalkError),

/// Error if the IPv6 extensions can not be serialized
/// because of internal consistency errors.
Ipv6Exts(ipv6_exts::ExtsWalkError),

/// Error if ICMPv6 is packaged in an IPv4 packet (it is undefined
/// how to calculate the checksum).
Icmpv6InIpv4,

/// Address size defined in the ARP header does not match the actual size.
ArpHeaderNotMatch,
}

impl From<Infallible> for BuildVecWriteError {
fn from(value: Infallible) -> Self {
match value {}
}
}

impl From<ValueTooBigError<usize>> for BuildVecWriteError {
fn from(value: ValueTooBigError<usize>) -> Self {
BuildVecWriteError::PayloadLen(value)
}
}

impl From<super::TransportChecksumError> for BuildVecWriteError {
fn from(value: super::TransportChecksumError) -> Self {
match value {
super::TransportChecksumError::PayloadLen(err) => BuildVecWriteError::PayloadLen(err),
super::TransportChecksumError::Icmpv6InIpv4 => BuildVecWriteError::Icmpv6InIpv4,
}
}
}

impl From<crate::WriteError<Infallible, ipv4_exts::ExtsWalkError>> for BuildVecWriteError {
fn from(value: crate::WriteError<Infallible, ipv4_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => match err {},
crate::WriteError::Content(err) => BuildVecWriteError::Ipv4Exts(err),
}
}
}

impl From<crate::WriteError<Infallible, ipv6_exts::ExtsWalkError>> for BuildVecWriteError {
fn from(value: crate::WriteError<Infallible, ipv6_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => match err {},
crate::WriteError::Content(err) => BuildVecWriteError::Ipv6Exts(err),
}
}
}

impl core::fmt::Display for BuildVecWriteError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use BuildVecWriteError::*;
match self {
PayloadLen(err) => err.fmt(f),
Ipv4Exts(err) => err.fmt(f),
Ipv6Exts(err) => err.fmt(f),
ArpHeaderNotMatch => write!(
f,
"address size defined in the ARP header does not match the actual size"
),
Icmpv6InIpv4 => write!(
f,
"Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."
),
}
}
}

impl core::error::Error for BuildVecWriteError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
use BuildVecWriteError::*;
match self {
PayloadLen(err) => Some(err),
Ipv4Exts(err) => Some(err),
Ipv6Exts(err) => Some(err),
Icmpv6InIpv4 => None,
ArpHeaderNotMatch => None,
}
}
}
44 changes: 44 additions & 0 deletions etherparse/src/err/packet/build_write_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,50 @@ impl core::error::Error for BuildWriteError {
}
}

#[cfg(feature = "std")]
impl From<std::io::Error> for BuildWriteError {
fn from(value: std::io::Error) -> Self {
BuildWriteError::Io(value)
}
}

#[cfg(feature = "std")]
impl From<ValueTooBigError<usize>> for BuildWriteError {
fn from(value: ValueTooBigError<usize>) -> Self {
BuildWriteError::PayloadLen(value)
}
}

#[cfg(feature = "std")]
impl From<super::TransportChecksumError> for BuildWriteError {
fn from(value: super::TransportChecksumError) -> Self {
match value {
super::TransportChecksumError::PayloadLen(err) => BuildWriteError::PayloadLen(err),
super::TransportChecksumError::Icmpv6InIpv4 => BuildWriteError::Icmpv6InIpv4,
}
}
}

#[cfg(feature = "std")]
impl From<crate::WriteError<std::io::Error, ipv4_exts::ExtsWalkError>> for BuildWriteError {
fn from(value: crate::WriteError<std::io::Error, ipv4_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => BuildWriteError::Io(err),
crate::WriteError::Content(err) => BuildWriteError::Ipv4Exts(err),
}
}
}

#[cfg(feature = "std")]
impl From<crate::WriteError<std::io::Error, ipv6_exts::ExtsWalkError>> for BuildWriteError {
fn from(value: crate::WriteError<std::io::Error, ipv6_exts::ExtsWalkError>) -> Self {
match value {
crate::WriteError::Io(err) => BuildWriteError::Io(err),
crate::WriteError::Content(err) => BuildWriteError::Ipv6Exts(err),
}
}
}

#[cfg(test)]
mod tests {
use super::{BuildWriteError::*, *};
Expand Down
8 changes: 8 additions & 0 deletions etherparse/src/err/packet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ mod build_write_error;
#[cfg(feature = "std")]
pub use build_write_error::*;

#[cfg(feature = "alloc")]
mod build_vec_write_error;
#[cfg(feature = "alloc")]
pub use build_vec_write_error::*;

mod build_slice_write_error;
pub use build_slice_write_error::*;

mod slice_error;
pub use slice_error::*;

Expand Down
7 changes: 4 additions & 3 deletions etherparse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@
// for docs.rs
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(test)]
#[cfg(any(feature = "alloc", test))]
extern crate alloc;
#[cfg(test)]
extern crate proptest;
Expand Down Expand Up @@ -343,6 +343,9 @@ mod compositions_tests;
mod helpers;
pub(crate) use helpers::*;

mod writer;
pub(crate) use writer::*;

mod lax_packet_headers;
pub use lax_packet_headers::*;

Expand All @@ -358,9 +361,7 @@ pub(crate) use lax_sliced_packet_cursor::*;
mod len_source;
pub use len_source::*;

#[cfg(feature = "std")]
mod packet_builder;
#[cfg(feature = "std")]
pub use crate::packet_builder::*;

mod packet_headers;
Expand Down
1 change: 1 addition & 0 deletions etherparse/src/link/single_vlan_header_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl<'a> SingleVlanHeaderSlice<'a> {
/// The caller must ensured that the given slice has the length of
/// [`SingleVlanHeader::LEN`]
#[inline]
#[cfg(feature = "std")]
pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> SingleVlanHeaderSlice {
SingleVlanHeaderSlice { slice }
}
Expand Down
27 changes: 20 additions & 7 deletions etherparse/src/net/ipv4_exts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,19 @@ impl Ipv4Extensions {
}

/// Write the extensions to the writer.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn write<T: std::io::Write + Sized>(
pub(crate) fn write_internal<T: CoreWrite + ?Sized>(
&self,
writer: &mut T,
start_ip_number: IpNumber,
) -> Result<(), err::ipv4_exts::HeaderWriteError> {
use err::ipv4_exts::{ExtsWalkError::*, HeaderWriteError::*};
) -> Result<(), WriteError<T::Error, err::ipv4_exts::ExtsWalkError>> {
use err::ipv4_exts::ExtsWalkError::*;
use ip_number::*;
match self.auth {
Some(ref header) => {
if AUTH == start_ip_number {
header.write(writer).map_err(Io)
writer.write_all(&header.to_bytes()).map_err(WriteError::Io)
} else {
Err(Content(ExtNotReferenced {
Err(WriteError::Content(ExtNotReferenced {
missing_ext: IpNumber::AUTHENTICATION_HEADER,
}))
}
Expand All @@ -183,6 +181,21 @@ impl Ipv4Extensions {
}
}

/// Write the extensions to the writer.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn write<T: std::io::Write + Sized>(
&self,
writer: &mut T,
start_ip_number: IpNumber,
) -> Result<(), err::ipv4_exts::HeaderWriteError> {
self.write_internal(&mut IoWriter(writer), start_ip_number)
.map_err(|err| match err {
WriteError::Io(err) => err::ipv4_exts::HeaderWriteError::Io(err),
WriteError::Content(err) => err::ipv4_exts::HeaderWriteError::Content(err),
})
}

///Length of the all present headers in bytes.
pub fn header_len(&self) -> usize {
if let Some(ref header) = self.auth {
Expand Down
Loading