Skip to content
Merged
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
2 changes: 1 addition & 1 deletion etherparse/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "etherparse"
version = "0.19.0"
version = "0.20.0"
authors = ["Julian Schmid <info@julianschmid.name>"]
edition = "2021"
repository = "https://github.com/JulianSchmid/etherparse"
Expand Down
4 changes: 2 additions & 2 deletions etherparse/examples/read_by_slicing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn main() {
ipv4.header().source_addr(),
ipv4.header().destination_addr()
);
if false == ipv4.extensions().is_empty() {
if !ipv4.extensions().is_empty() {
println!(" {:?}", ipv4.extensions());
}
}
Expand All @@ -85,7 +85,7 @@ fn main() {
ipv6.header().source_addr(),
ipv6.header().destination_addr()
);
if false == ipv6.extensions().is_empty() {
if !ipv6.extensions().is_empty() {
println!(" {:?}", ipv6.extensions());
}
}
Expand Down
6 changes: 3 additions & 3 deletions etherparse/src/compositions_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl<'a> ComponentTest<'a> {
None => {}
}
use std::io::Write;
buffer.write(&self.payload[..]).unwrap();
buffer.write_all(self.payload).unwrap();
buffer
}

Expand Down Expand Up @@ -341,14 +341,14 @@ impl<'a> ComponentTest<'a> {
fn assert_headers(&self, actual: PacketHeaders) {
assert_eq!(self.link, actual.link);
assert_eq!(self.link_exts, actual.link_exts);
assert_eq!(self.net, self.net);
assert_eq!(self.net, actual.net);
assert_eq!(self.transport, actual.transport);
assert_eq!(self.payload[..], actual.payload.slice()[..]);
}

fn assert_sliced_packet(&self, result: SlicedPacket) {
//assert identity to touch the derives (code coverage hack)
assert_eq!(result, result);
assert_eq!(result.clone(), result);

//ethernet & link extensions
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion etherparse/src/net/net_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::*;
since = "0.14.0",
note = "Deprecated use crate::NetSlice or crate::IpSlice instead"
)]
pub use NetSlice as InternetSlice;
pub use self::NetSlice as InternetSlice;

/// Slice containing the network headers & payloads (e.g. IPv4, IPv6, ARP).
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down
92 changes: 34 additions & 58 deletions etherparse/src/transport/icmpv4_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,23 @@ impl<'a> Icmpv4Slice<'a> {

// check type specific length
match icmp_type {
TYPE_TIMESTAMP => {
if 0 == icmp_code && TimestampMessage::LEN != slice.len() {
return Err(err::LenError {
required_len: TimestampMessage::LEN,
len: slice.len(),
len_source: LenSource::Slice,
layer: err::Layer::Icmpv4Timestamp,
layer_start_offset: 0,
});
}
TYPE_TIMESTAMP if 0 == icmp_code && TimestampMessage::LEN != slice.len() => {
return Err(err::LenError {
required_len: TimestampMessage::LEN,
len: slice.len(),
len_source: LenSource::Slice,
layer: err::Layer::Icmpv4Timestamp,
layer_start_offset: 0,
});
}
TYPE_TIMESTAMP_REPLY => {
if 0 == icmp_code && TimestampMessage::LEN != slice.len() {
return Err(err::LenError {
required_len: TimestampMessage::LEN,
len: slice.len(),
len_source: LenSource::Slice,
layer: err::Layer::Icmpv4TimestampReply,
layer_start_offset: 0,
});
}
TYPE_TIMESTAMP_REPLY if 0 == icmp_code && TimestampMessage::LEN != slice.len() => {
return Err(err::LenError {
required_len: TimestampMessage::LEN,
len: slice.len(),
len_source: LenSource::Slice,
layer: err::Layer::Icmpv4TimestampReply,
layer_start_offset: 0,
});
}
_ => {}
}
Expand All @@ -82,13 +78,7 @@ impl<'a> Icmpv4Slice<'a> {
#[inline]
pub fn header_len(&self) -> usize {
match self.type_u8() {
TYPE_TIMESTAMP | TYPE_TIMESTAMP_REPLY => {
if 0 == self.code_u8() {
TimestampMessage::LEN
} else {
8
}
}
TYPE_TIMESTAMP | TYPE_TIMESTAMP_REPLY if 0 == self.code_u8() => TimestampMessage::LEN,
_ => 8,
}
}
Expand All @@ -108,10 +98,8 @@ impl<'a> Icmpv4Slice<'a> {
}

match self.type_u8() {
TYPE_ECHO_REPLY => {
if 0 == self.code_u8() {
return EchoReply(IcmpEchoHeader::from_bytes(self.bytes5to8()));
}
TYPE_ECHO_REPLY if 0 == self.code_u8() => {
return EchoReply(IcmpEchoHeader::from_bytes(self.bytes5to8()));
}
TYPE_DEST_UNREACH => {
use DestUnreachableHeader::*;
Expand Down Expand Up @@ -172,10 +160,8 @@ impl<'a> Icmpv4Slice<'a> {
});
}
}
TYPE_ECHO_REQUEST => {
if 0 == self.code_u8() {
return EchoRequest(IcmpEchoHeader::from_bytes(self.bytes5to8()));
}
TYPE_ECHO_REQUEST if 0 == self.code_u8() => {
return EchoRequest(IcmpEchoHeader::from_bytes(self.bytes5to8()));
}
TYPE_TIME_EXCEEDED => {
use TimeExceededCode::*;
Expand Down Expand Up @@ -209,24 +195,20 @@ impl<'a> Icmpv4Slice<'a> {
_ => {}
}
}
TYPE_TIMESTAMP => {
if 0 == self.code_u8() {
// SAFETY:
// Safe as the contructor checks that the slice has
// the length of TimestampMessage::SERIALIZED_SIZE (20).
unsafe {
return TimestampRequest(timestamp_message(self.slice.as_ptr()));
}
TYPE_TIMESTAMP if 0 == self.code_u8() => {
// SAFETY:
// Safe as the contructor checks that the slice has
// the length of TimestampMessage::SERIALIZED_SIZE (20).
unsafe {
return TimestampRequest(timestamp_message(self.slice.as_ptr()));
}
}
TYPE_TIMESTAMP_REPLY => {
if 0 == self.code_u8() {
// SAFETY:
// Safe as the contructor checks that the slice has
// the length of TimestampMessage::SERIALIZED_SIZE (20).
unsafe {
return TimestampReply(timestamp_message(self.slice.as_ptr()));
}
TYPE_TIMESTAMP_REPLY if 0 == self.code_u8() => {
// SAFETY:
// Safe as the contructor checks that the slice has
// the length of TimestampMessage::SERIALIZED_SIZE (20).
unsafe {
return TimestampReply(timestamp_message(self.slice.as_ptr()));
}
}
_ => {}
Expand Down Expand Up @@ -307,13 +289,7 @@ impl<'a> Icmpv4Slice<'a> {
// Length safe as the contructor checks that the slice has
// the length of TimestampMessage::SERIALIZED_SIZE (20)
// for the messages types TYPE_TIMESTAMP and TYPE_TIMESTAMP_REPLY.
TYPE_TIMESTAMP | TYPE_TIMESTAMP_REPLY => {
if 0 == self.code_u8() {
TimestampMessage::LEN
} else {
8
}
}
TYPE_TIMESTAMP | TYPE_TIMESTAMP_REPLY if 0 == self.code_u8() => TimestampMessage::LEN,
// SAFETY:
// Length safe as the contructor checks that the slice has
// at least the length of Icmpv4Header::MIN_LEN(8) for
Expand Down
36 changes: 36 additions & 0 deletions etherparse/src/transport/icmpv6/icmpv6_payload/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ impl Icmpv6Payload {
}
}

/// Returns true if the serialized payload is empty.
#[inline]
pub fn is_empty(&self) -> bool {
0 == self.len()
}

/// Write the fixed payload bytes to the writer.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
Expand All @@ -59,13 +65,43 @@ impl Icmpv6Payload {
#[cfg(test)]
mod tests {
use super::*;
use core::net::Ipv6Addr;
use proptest::prelude::*;

#[test]
fn router_solicitation_payload_to_bytes() {
assert_eq!([] as [u8; 0], RouterSolicitationPayload.to_bytes());
}

#[test]
fn payload_is_empty() {
assert!(Icmpv6Payload::RouterSolicitation(RouterSolicitationPayload).is_empty());
assert!(
!Icmpv6Payload::RouterAdvertisement(RouterAdvertisementPayload {
reachable_time: 1,
retrans_timer: 2,
})
.is_empty()
);
assert!(
!Icmpv6Payload::NeighborSolicitation(NeighborSolicitationPayload {
target_address: Ipv6Addr::LOCALHOST,
})
.is_empty()
);
assert!(
!Icmpv6Payload::NeighborAdvertisement(NeighborAdvertisementPayload {
target_address: Ipv6Addr::LOCALHOST,
})
.is_empty()
);
assert!(!Icmpv6Payload::Redirect(RedirectPayload {
target_address: Ipv6Addr::LOCALHOST,
destination_address: Ipv6Addr::UNSPECIFIED,
})
.is_empty());
}

proptest! {
#[test]
fn payloads_to_bytes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,7 @@ impl PrefixInformation {
// Safe to unwrap because `bytes` originates from `[u8; Self::LEN]` and
// the chunk sizes below exactly cover `Self::LEN` (32 bytes).
let (type_and_len, rest) = bytes.split_first_chunk::<2>().unwrap();
if *type_and_len
!= [
NdpOptionType::PREFIX_INFORMATION.0,
Self::LENGTH_UNITS,
]
{
if *type_and_len != [NdpOptionType::PREFIX_INFORMATION.0, Self::LENGTH_UNITS] {
return Err(NdpOptionReadError::UnexpectedHeader {
expected_option_id: NdpOptionType::PREFIX_INFORMATION,
actual_option_id: NdpOptionType(type_and_len[0]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ impl<'a> PrefixInformationOptionSlice<'a> {

pub fn from_slice(slice: &'a [u8]) -> Result<Self, NdpOptionReadError> {
let slice: &'a [u8; PrefixInformation::LEN] =
slice.try_into().map_err(|_| NdpOptionReadError::UnexpectedSize {
option_id: NdpOptionType::PREFIX_INFORMATION,
expected_size: PrefixInformation::LEN,
actual_size: slice.len(),
})?;
slice
.try_into()
.map_err(|_| NdpOptionReadError::UnexpectedSize {
option_id: NdpOptionType::PREFIX_INFORMATION,
expected_size: PrefixInformation::LEN,
actual_size: slice.len(),
})?;
// Validate the encoded option header (`Type` and `Length`) as well.
PrefixInformation::from_bytes(*slice)?;
Ok(Self { slice })
Expand Down
3 changes: 2 additions & 1 deletion etherparse/src/transport/icmpv6/ndp_option_read_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ pub enum NdpOptionReadError {
/// An ND option with a length value of zero was encountered.
ZeroLength { option_id: NdpOptionType },
/// The option has a fixed encoded size and the received size differs.
UnexpectedSize { option_id: NdpOptionType,
UnexpectedSize {
option_id: NdpOptionType,
expected_size: usize,
actual_size: usize,
},
Expand Down
29 changes: 12 additions & 17 deletions etherparse/src/transport/icmpv6/ndp_options_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ impl<'a> NdpOptionsIterator<'a> {
self.options
}

fn parse_next_option(
&mut self,
) -> Result<NdpOptionSlice<'a>, NdpOptionReadError> {
fn parse_next_option(&mut self) -> Result<NdpOptionSlice<'a>, NdpOptionReadError> {
use NdpOptionReadError::*;

let (header, _) = NdpOptionHeader::from_slice(self.options)?;
Expand All @@ -34,12 +32,14 @@ impl<'a> NdpOptionsIterator<'a> {
}

let option_len = header.byte_len();
let (option, rest) = self.options.split_at_checked(option_len)
.ok_or_else(|| UnexpectedEndOfSlice {
option_id,
expected_size: option_len,
actual_size: self.options.len(),
})?;
let (option, rest) =
self.options
.split_at_checked(option_len)
.ok_or(UnexpectedEndOfSlice {
option_id,
expected_size: option_len,
actual_size: self.options.len(),
})?;

let parsed = match option_id {
NdpOptionType::SOURCE_LINK_LAYER_ADDRESS => {
Expand All @@ -50,15 +50,11 @@ impl<'a> NdpOptionsIterator<'a> {
TargetLinkLayerAddressOptionSlice::from_slice(option)
.map(NdpOptionSlice::TargetLinkLayerAddress)
}
NdpOptionType::PREFIX_INFORMATION => {
PrefixInformationOptionSlice::from_slice(option)
.map(NdpOptionSlice::PrefixInformation)
}
NdpOptionType::PREFIX_INFORMATION => PrefixInformationOptionSlice::from_slice(option)
.map(NdpOptionSlice::PrefixInformation),
NdpOptionType::REDIRECTED_HEADER => RedirectedHeaderOptionSlice::from_slice(option)
.map(NdpOptionSlice::RedirectedHeader),
NdpOptionType::MTU => {
MtuOptionSlice::from_slice(option).map(NdpOptionSlice::Mtu)
}
NdpOptionType::MTU => MtuOptionSlice::from_slice(option).map(NdpOptionSlice::Mtu),
_ => UnknownNdpOptionSlice::from_slice(option).map(NdpOptionSlice::Unknown),
}?;

Expand Down Expand Up @@ -108,7 +104,6 @@ mod tests {
use super::*;
use crate::icmpv6::PrefixInformation;


#[test]
fn from_slice_and_rest() {
let buffer = [1, 1, 1, 2, 3, 4, 5, 6];
Expand Down
Loading
Loading