Expand description
Low-level packet access and construction.
§An overview over packet representations
The wire module deals with the packet representation. It provides three levels of
functionality.
- First, it provides functions to extract fields from sequences of octets, and to insert fields
into sequences of octets. This happens in the lowercase structures e.g.
ethernet_frameorudp_packet1. - Second, it provides a compact, high-level representation of header data that can be created from
parsing and emitted into a sequence of octets. This happens through the
Reprfamily of structs and enums, e.g.ArpReprorIpv4Repr. - Third, it provides an type wrapper around sequences of octets valid as a particular packet
format which potentially owns its data. This can memoize parts of the layout, avoiding
re-calculating it on every access. While this restricts mutability of header data, fixed-length
checksum fields and the payload can still be accessed normally. This happens in the uppercase
Frame or Packet family of structs, e.g.
ArpPacketorUdpPacket.
An important part is also the underlying trait for byte containers, Payload and PayloadMut.
None of the standard reference traits accurately captures the relationship of a framing outer
packet with its payload. It should be the case that the payload content changes only when accessed
directly and changing its length should be possible. These two traits model such a relationship,
providing a few methods to efficiently request layout changes of the payload from the container.
This makes it possible to recursively parse packets while being able to resize the innermost packet
or to insert additional data into an intermediate layer without mutating the payload.
The packet family of data structures guarantees that, if the packet::check_len() method
returned Ok(()), then no field accessor or setter method will panic; however, the guarantee only
hold while specific fields are mutated, which are listed in the documentation for the specific
packet.
The owning Packet family makes a stronger guarantee. It only exposes fields for which mutation
will not cause panics (some panics are still possible, read on), as long as Packet::new_checked
constructor was used or the new_unchecked constructor with previously parsed data. Where such a
mutation causes the layout to change (i.e. payload length) the underlying container is first asked
to perform the necessary reframing and then dependent fields and offsets are updated. Note that
this ties panicking to the container: A misbehaving implementation that implements the PayloadMut
trait incorrectly or a fallible allocation could still cause panics.
The packet::new_unchecked method is a shorthand for combining new_unchecked and check_len
while the Packet::new_checked method is a shorthand for a combination of Packet::new_unchecked
and Repr::parse. When parsing untrusted input, it is necessary to use either of the checked
methods; so long as the buffer is not modified, no accessor will fail. When emitting output,
though, it is incorrect to use Packet::new_checked(); the length check is likely to succeed on
a zeroed buffer, but fail on a buffer filled with data from a previous packet, such as when reusing
buffers, resulting in nondeterministic panics with some network devices but not others. The buffer
length for emission is often calculated by the Repr struct but not in general provided by the
Packet layer.
In the Repr family of data structures, the Repr::parse() method never panics and the
Repr::emit() method never panics as long as the underlying buffer is exactly Repr::buffer_len()
octets long if provided.
§Examples
To emit an IP packet header into an octet buffer, and then parse it back:
use ethox::wire::{ip::v4, Checksum, ip::Protocol};
let repr = v4::Repr {
src_addr: v4::Address::new(10, 0, 0, 1),
dst_addr: v4::Address::new(10, 0, 0, 2),
protocol: Protocol::Tcp,
payload_len: 10,
hop_limit: 64
};
let mut buffer = vec![0; repr.buffer_len() + repr.payload_len];
{ // emission
let packet = v4::packet::new_unchecked_mut(&mut buffer);
repr.emit(packet, Checksum::Manual);
}
{ // parsing
let packet = v4::packet::new_checked(&buffer)
.expect("truncated packet");
let parsed = v4::Repr::parse(packet, Checksum::Manual)
.expect("malformed packet");
assert_eq!(repr, parsed);
}The TCP structures differ since I haven’t gotten around to reworking them. It does not have a dynamically sized byte wrapper so its
Packetimplements this functionality as well but come with all downsides. In particular, its accessors may panic. ↩
Re-exports§
pub use self::pretty_print::PrettyPrinter;
Modules§
Structs§
- Reframe
- Groups parameters and utilities for payload reframing.
- Reframe
Payload - Describes the resizing that keeps a payload intact.
- payload
- A dynamically sized type representing a packet payload.
Enums§
- Checksum
- Describes how to handle checksums.
- Error
- The error type for parsing of the network stack.
- Payload
Error - Error variants for resizing.
Traits§
- Payload
- A specialized, internal variant of
Borrow<payload>. - Payload
Mut - A specialized, internal variant of
BorrowMut<payload>. - Payload
MutExt - Extends the mutable payload structures with new reorganization methods.
Type Aliases§
- Payload
Result - The result type of a reframing operation on
PayloadMut. - Result
- The result type for the networking stack.