etherparse/lib.rs
1//! A zero allocation supporting library for parsing & writing a bunch of packet based protocols (EthernetII, IPv4, IPv6, UDP, TCP ...).
2//!
3//! Currently supported are:
4//! * Ethernet II
5//! * IEEE 802.1Q VLAN Tagging Header
6//! * MACsec (IEEE 802.1AE)
7//! * ARP
8//! * IPv4
9//! * IPv6 (supporting the most common extension headers, but not all)
10//! * UDP
11//! * TCP
12//! * ICMP & ICMPv6 (not all message types are supported)
13//!
14//! Reconstruction of fragmented IP packets is also supported, but requires allocations.
15//!
16//! # Usage
17//!
18//! Add the following to your `Cargo.toml`:
19//!
20//! ```toml
21//! [dependencies]
22//! etherparse = "0.18"
23//! ```
24//!
25//! # What is etherparse?
26//!
27//! Etherparse is intended to provide the basic network parsing functions that allow for easy analysis, transformation or generation of recorded network data.
28//!
29//! Some key points are:
30//!
31//! * It is completely written in Rust and thoroughly tested.
32//! * Special attention has been paid to not use allocations or syscalls.
33//! * The package is still in development and can & will still change.
34//! * The current focus of development is on the most popular protocols in the internet & transport layer.
35//!
36//! # How to parse network packages?
37//! Etherparse gives you two options for parsing network packages automatically:
38//!
39//! ## Slicing the packet
40//! Here the different components in a packet are separated without parsing all their fields. For each header a slice is generated that allows access to the fields of a header.
41//! ```
42//! # use etherparse::{SlicedPacket, PacketBuilder};
43//! # let builder = PacketBuilder::
44//! # ethernet2([1,2,3,4,5,6], //source mac
45//! # [7,8,9,10,11,12]) //destination mac
46//! # .ipv4([192,168,1,1], //source ip
47//! # [192,168,1,2], //destination ip
48//! # 20) //time to life
49//! # .udp(21, //source port
50//! # 1234); //destination port
51//! # //payload of the udp packet
52//! # let payload = [1,2,3,4,5,6,7,8];
53//! # //get some memory to store the serialized data
54//! # let mut packet = Vec::<u8>::with_capacity(
55//! # builder.size(payload.len()));
56//! # builder.write(&mut packet, &payload).unwrap();
57//! match SlicedPacket::from_ethernet(&packet) {
58//! Err(value) => println!("Err {:?}", value),
59//! Ok(value) => {
60//! println!("link: {:?}", value.link);
61//! println!("link_exts: {:?}", value.link_exts); // contains vlan & macsec
62//! println!("net: {:?}", value.net); // contains ip & arp
63//! println!("transport: {:?}", value.transport);
64//! }
65//! };
66//! ```
67//! This is the faster option if your code is not interested in all fields of all the headers. It is a good choice if you just want filter or find packages based on a subset of the headers and/or their fields.
68//!
69//! Depending from which point downward you want to slice a package check out the functions:
70//!
71//! * [`SlicedPacket::from_ethernet`] for parsing from an Ethernet II header downwards
72//! * [`SlicedPacket::from_linux_sll`] for parsing from a Linux Cooked Capture v1 (SLL) downwards
73//! * [`SlicedPacket::from_ether_type`] for parsing a slice starting after an Ethernet II header
74//! * [`SlicedPacket::from_ip`] for parsing from an IPv4 or IPv6 downwards
75//!
76//! In case you want to parse cut off packets (e.g. packets returned in in ICMP message) you can use the "lax" parsing methods:
77//!
78//! * [`LaxSlicedPacket::from_ethernet`] for parsing from an Ethernet II header downwards
79//! * [`LaxSlicedPacket::from_ether_type`] for parsing a slice starting after an Ethernet II header
80//! * [`LaxSlicedPacket::from_ip`] for parsing from an IPv4 or IPv6 downwards
81//!
82//! ## Deserializing all headers into structs
83//!
84//! This option deserializes all known headers and transfers their contents to header structs.
85//! ```rust
86//! # use etherparse::{PacketHeaders, PacketBuilder};
87//! # let builder = PacketBuilder::
88//! # ethernet2([1,2,3,4,5,6], //source mac
89//! # [7,8,9,10,11,12]) //destination mac
90//! # .ipv4([192,168,1,1], //source ip
91//! # [192,168,1,2], //destination ip
92//! # 20) //time to life
93//! # .udp(21, //source port
94//! # 1234); //destination port
95//! # //payload of the udp packet
96//! # let payload = [1,2,3,4,5,6,7,8];
97//! # //get some memory to store the serialized data
98//! # let mut packet = Vec::<u8>::with_capacity(
99//! # builder.size(payload.len()));
100//! # builder.write(&mut packet, &payload).unwrap();
101//! match PacketHeaders::from_ethernet_slice(&packet) {
102//! Err(value) => println!("Err {:?}", value),
103//! Ok(value) => {
104//! println!("link: {:?}", value.link);
105//! println!("link_exts: {:?}", value.link_exts); // contains vlan & macsec
106//! println!("net: {:?}", value.net); // contains ip & arp
107//! println!("transport: {:?}", value.transport);
108//! }
109//! };
110//! ```
111//! This option is slower then slicing when only few fields are accessed. But it can be the faster option or useful if you are interested in most fields anyways or if you want to re-serialize the headers with modified values.
112//!
113//! Depending from which point downward you want to unpack a package check out the functions
114//!
115//! * [`PacketHeaders::from_ethernet_slice`] for parsing from an Ethernet II header downwards
116//! * [`PacketHeaders::from_ether_type`] for parsing a slice starting after an Ethernet II header
117//! * [`PacketHeaders::from_ip_slice`] for parsing from an IPv4 or IPv6 downwards
118//!
119//! In case you want to parse cut off packets (e.g. packets returned in in ICMP message) you can use the "lax" parsing methods:
120//!
121//! * [`LaxPacketHeaders::from_ethernet`] for parsing from an Ethernet II header downwards
122//! * [`LaxPacketHeaders::from_ether_type`] for parsing a slice starting after an Ethernet II header
123//! * [`LaxPacketHeaders::from_ip`] for parsing from an IPv4 or IPv6 downwards
124//!
125//! ## Manually slicing only one packet layer
126//!
127//! It is also possible to only slice one packet layer:
128//!
129//! * [`Ethernet2Slice::from_slice_without_fcs`] & [`Ethernet2Slice::from_slice_with_crc32_fcs`]
130//! * [`LinuxSllSlice::from_slice`]
131//! * [`SingleVlanSlice::from_slice`]
132//! * [`MacsecSlice::from_slice`]
133//! * [`IpSlice::from_slice`] & [`LaxIpSlice::from_slice`]
134//! * [`Ipv4Slice::from_slice`] & [`LaxIpv4Slice::from_slice`]
135//! * [`Ipv6Slice::from_slice`] & [`LaxIpv6Slice::from_slice`]
136//! * [`UdpSlice::from_slice`] & [`UdpSlice::from_slice_lax`]
137//! * [`TcpSlice::from_slice`]
138//! * [`Icmpv4Slice::from_slice`]
139//! * [`Icmpv6Slice::from_slice`]
140//!
141//! The resulting data types allow access to both the header(s) and the payload of the layer
142//! and will automatically limit the length of payload if the layer has a length field limiting the
143//! payload (e.g. the payload of IPv6 packets will be limited by the "payload length" field in
144//! an IPv6 header).
145//!
146//! ## Manually slicing & parsing only headers
147//!
148//! It is also possible just to parse headers. Have a look at the documentation for the
149//! following \[NAME\]HeaderSlice.from_slice methods, if you want to just slice the header:
150//!
151//! * [`Ethernet2HeaderSlice::from_slice`]
152//! * [`LinuxSllHeaderSlice::from_slice`]
153//! * [`SingleVlanHeaderSlice::from_slice`]
154//! * [`MacsecHeaderSlice::from_slice`]
155//! * [`ArpPacketSlice::from_slice`]
156//! * [`Ipv4HeaderSlice::from_slice`]
157//! * [`Ipv4ExtensionsSlice::from_slice`]
158//! * [`Ipv6HeaderSlice::from_slice`]
159//! * [`Ipv6ExtensionsSlice::from_slice`]
160//! * [`Ipv6RawExtHeaderSlice::from_slice`]
161//! * [`IpAuthHeaderSlice::from_slice`]
162//! * [`Ipv6FragmentHeaderSlice::from_slice`]
163//! * [`UdpHeaderSlice::from_slice`]
164//! * [`TcpHeaderSlice::from_slice`]
165//!
166//! And for deserialization into the corresponding header structs have a look at:
167//!
168//! * [`Ethernet2Header::read`] & [`Ethernet2Header::from_slice`]
169//! * [`LinuxSllHeader::read`] & [`LinuxSllHeader::from_slice`]
170//! * [`SingleVlanHeader::read`] & [`SingleVlanHeader::from_slice`]
171//! * [`MacsecHeader::read`] & [`MacsecHeader::from_slice`]
172//! * [`ArpPacket::read`] & [`ArpPacket::from_slice`]
173//! * [`IpHeaders::read`] & [`IpHeaders::from_slice`]
174//! * [`Ipv4Header::read`] & [`Ipv4Header::from_slice`]
175//! * [`Ipv4Extensions::read`] & [`Ipv4Extensions::from_slice`]
176//! * [`Ipv6Header::read`] & [`Ipv6Header::from_slice`]
177//! * [`Ipv6Extensions::read`] & [`Ipv6Extensions::from_slice`]
178//! * [`Ipv6RawExtHeader::read`] & [`Ipv6RawExtHeader::from_slice`]
179//! * [`IpAuthHeader::read`] & [`IpAuthHeader::from_slice`]
180//! * [`Ipv6FragmentHeader::read`] & [`Ipv6FragmentHeader::from_slice`]
181//! * [`UdpHeader::read`] & [`UdpHeader::from_slice`]
182//! * [`TcpHeader::read`] & [`TcpHeader::from_slice`]
183//! * [`Icmpv4Header::read`] & [`Icmpv4Header::from_slice`]
184//! * [`Icmpv6Header::read`] & [`Icmpv6Header::from_slice`]
185//!
186//! # How to generate fake packet data?
187//!
188//! ## Packet Builder
189//!
190//! The PacketBuilder struct provides a high level interface for quickly creating network packets. The PacketBuilder will automatically set fields which can be deduced from the content and compositions of the packet itself (e.g. checksums, lengths, ethertype, ip protocol number).
191//!
192//! [Example:](https://github.com/JulianSchmid/etherparse/blob/0.14.3/examples/write_udp.rs)
193//! ```rust
194//! use etherparse::PacketBuilder;
195//!
196//! let builder = PacketBuilder::
197//! ethernet2([1,2,3,4,5,6], //source mac
198//! [7,8,9,10,11,12]) //destination mac
199//! .ipv4([192,168,1,1], //source ip
200//! [192,168,1,2], //destination ip
201//! 20) //time to life
202//! .udp(21, //source port
203//! 1234); //destination port
204//!
205//! //payload of the udp packet
206//! let payload = [1,2,3,4,5,6,7,8];
207//!
208//! //get some memory to store the result
209//! let mut result = Vec::<u8>::with_capacity(builder.size(payload.len()));
210//!
211//! //serialize
212//! //this will automatically set all length fields, checksums and identifiers (ethertype & protocol)
213//! //before writing the packet out to "result"
214//! builder.write(&mut result, &payload).unwrap();
215//! ```
216//!
217//! There is also an [example for TCP packets](https://github.com/JulianSchmid/etherparse/blob/0.14.3/examples/write_tcp.rs) available.
218//!
219//! Check out the [PacketBuilder documentation](struct.PacketBuilder.html) for more information.
220//!
221//! ## Manually serializing each header
222//!
223//! Alternatively it is possible to manually build a packet
224//! ([example](https://github.com/JulianSchmid/etherparse/blob/0.14.3/examples/write_ipv4_udp.rs)).
225//! Generally each struct representing a header has a "write" method that allows it to be
226//! serialized. These write methods sometimes automatically calculate checksums and fill them
227//! in. In case this is unwanted behavior (e.g. if you want to generate a packet with an invalid
228//! checksum), it is also possible to call a "write_raw" method that will simply serialize the data
229//! without doing checksum calculations.
230//!
231//! Read the documentations of the different methods for a more details:
232//!
233//! * [`Ethernet2Header::to_bytes`] & [`Ethernet2Header::write`]
234//! * [`LinuxSllHeader::to_bytes`] & [`LinuxSllHeader::write`]
235//! * [`SingleVlanHeader::to_bytes`] & [`SingleVlanHeader::write`]
236//! * [`MacsecHeader::to_bytes`] & [`MacsecHeader::write`]
237//! * [`ArpPacket::to_bytes`] & [`ArpPacket::write`]
238//! * [`ArpEthIpv4Packet::to_bytes`]
239//! * [`Ipv4Header::to_bytes`] & [`Ipv4Header::write`] & [`Ipv4Header::write_raw`]
240//! * [`Ipv4Extensions::write`]
241//! * [`Ipv6Header::to_bytes`] & [`Ipv6Header::write`]
242//! * [`Ipv6Extensions::write`]
243//! * [`Ipv6RawExtHeader::to_bytes`] & [`Ipv6RawExtHeader::write`]
244//! * [`IpAuthHeader::to_bytes`] & [`IpAuthHeader::write`]
245//! * [`Ipv6FragmentHeader::to_bytes`] & [`Ipv6FragmentHeader::write`]
246//! * [`UdpHeader::to_bytes`] & [`UdpHeader::write`]
247//! * [`TcpHeader::to_bytes`] & [`TcpHeader::write`]
248//! * [`Icmpv4Header::to_bytes`] & [`Icmpv4Header::write`]
249//! * [`Icmpv6Header::to_bytes`] & [`Icmpv6Header::write`]
250//!
251//! # References
252//! * Darpa Internet Program Protocol Specification [RFC 791](https://tools.ietf.org/html/rfc791)
253//! * Internet Protocol, Version 6 (IPv6) Specification [RFC 8200](https://tools.ietf.org/html/rfc8200)
254//! * [IANA 802 EtherTypes](https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml)
255//! * [IANA Protocol Numbers](https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml)
256//! * [Internet Protocol Version 6 (IPv6) Parameters](https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml)
257//! * [Wikipedia IEEE_802.1Q](https://en.wikipedia.org/w/index.php?title=IEEE_802.1Q&oldid=820983900)
258//! * User Datagram Protocol (UDP) [RFC 768](https://tools.ietf.org/html/rfc768)
259//! * Transmission Control Protocol [RFC 793](https://tools.ietf.org/html/rfc793)
260//! * TCP Extensions for High Performance [RFC 7323](https://tools.ietf.org/html/rfc7323)
261//! * The Addition of Explicit Congestion Notification (ECN) to IP [RFC 3168](https://tools.ietf.org/html/rfc3168)
262//! * Robust Explicit Congestion Notification (ECN) Signaling with Nonces [RFC 3540](https://tools.ietf.org/html/rfc3540)
263//! * IP Authentication Header [RFC 4302](https://tools.ietf.org/html/rfc4302)
264//! * Mobility Support in IPv6 [RFC 6275](https://tools.ietf.org/html/rfc6275)
265//! * Host Identity Protocol Version 2 (HIPv2) [RFC 7401](https://tools.ietf.org/html/rfc7401)
266//! * Shim6: Level 3 Multihoming Shim Protocol for IPv6 [RFC 5533](https://tools.ietf.org/html/rfc5533)
267//! * Computing the Internet Checksum [RFC 1071](https://datatracker.ietf.org/doc/html/rfc1071)
268//! * Internet Control Message Protocol [RFC 792](https://datatracker.ietf.org/doc/html/rfc792)
269//! * [IANA Internet Control Message Protocol (ICMP) Parameters](https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml)
270//! * Requirements for Internet Hosts -- Communication Layers [RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)
271//! * Requirements for IP Version 4 Routers [RFC 1812](https://datatracker.ietf.org/doc/html/rfc1812)
272//! * Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification [RFC 4443](https://datatracker.ietf.org/doc/html/rfc4443)
273//! * ICMP Router Discovery Messages [RFC 1256](https://datatracker.ietf.org/doc/html/rfc1256)
274//! * [Internet Control Message Protocol version 6 (ICMPv6) Parameters](https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml)
275//! * Multicast Listener Discovery (MLD) for IPv6 [RFC 2710](https://datatracker.ietf.org/doc/html/rfc2710)
276//! * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861)
277//! * [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) on tcpdump
278//! * LINUX_SLL [header definition](https://github.com/the-tcpdump-group/libpcap/blob/a932566fa1f6df16176ac702b1762ea1cd9ed9a3/pcap/sll.h) on libpcap
279//! * [Linux packet types definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel
280//! * Address Resolution Protocol (ARP) Parameters [Harware Types](https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2)
281//! * [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel
282//! * ["IEEE Standard for Local and metropolitan area networks-Media Access Control (MAC) Security," in IEEE Std 802.1AE-2018 (Revision of IEEE Std 802.1AE-2006) , vol., no., pp.1-239, 26 Dec. 2018, doi: 10.1109/IEEESTD.2018.8585421.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8585421&isnumber=8585420)
283//! * ["IEEE Standard for Local and metropolitan area networks--Media Access Control (MAC) Security Corrigendum 1: Tag Control Information Figure," in IEEE Std 802.1AE-2018/Cor 1-2020 (Corrigendum to IEEE Std 802.1AE-2018) , vol., no., pp.1-14, 21 July 2020, doi: 10.1109/IEEESTD.2020.9144679.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9144679&isnumber=9144678)
284
285// # Reason for 'bool_comparison' disable:
286//
287// Clippy triggers triggers errors like the following if the warning stays enabled:
288//
289// warning: equality checks against false can be replaced by a negation
290// --> src/packet_decoder.rs:131:20
291// |
292// 131 | if false == fragmented {
293// | ^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!fragmented`
294//
295//
296// I prefer to write `false == value` instead of `!value` as it
297// is more visually striking and is not as easy to overlook as the single
298// character '!'.
299#![allow(clippy::bool_comparison)]
300// Removes all std and alloc default imports & enables "non std" support.
301#![no_std]
302// enables https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html
303// for docs.rs
304#![cfg_attr(docsrs, feature(doc_cfg))]
305
306#[cfg(test)]
307extern crate alloc;
308#[cfg(test)]
309extern crate proptest;
310#[cfg(any(feature = "std", test))]
311extern crate std;
312
313/// Module containing error types that can be triggered.
314pub mod err;
315
316/// Module containing helpers to re-assemble fragmented packets (contains allocations).
317#[cfg(feature = "std")]
318#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
319pub mod defrag;
320
321mod link;
322pub use link::*;
323
324#[cfg(test)]
325pub(crate) mod test_gens;
326
327mod net;
328pub use net::*;
329
330#[cfg(feature = "std")]
331#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
332pub mod io;
333
334mod transport;
335pub use transport::*;
336
337/// Helpers for calculating checksums.
338pub mod checksum;
339
340#[cfg(test)]
341mod compositions_tests;
342
343mod helpers;
344pub(crate) use helpers::*;
345
346mod lax_packet_headers;
347pub use lax_packet_headers::*;
348
349mod lax_payload_slice;
350pub use lax_payload_slice::*;
351
352mod lax_sliced_packet;
353pub use lax_sliced_packet::*;
354
355mod lax_sliced_packet_cursor;
356pub(crate) use lax_sliced_packet_cursor::*;
357
358mod len_source;
359pub use len_source::*;
360
361#[cfg(feature = "std")]
362mod packet_builder;
363#[cfg(feature = "std")]
364pub use crate::packet_builder::*;
365
366mod packet_headers;
367pub use crate::packet_headers::*;
368
369mod payload_slice;
370pub use crate::payload_slice::*;
371
372mod sliced_packet;
373pub use crate::sliced_packet::*;
374
375mod sliced_packet_cursor;
376pub(crate) use sliced_packet_cursor::*;
377
378#[cfg(test)]
379pub(crate) mod test_packet;
380
381/// Deprecated use [err::ReadError] instead or use the specific error type returned by operation you are using.
382#[cfg(feature = "std")]
383#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
384#[deprecated(
385 since = "0.14.0",
386 note = "Please use the type err::ReadError instead or use the specific error type returned by operation you are using."
387)]
388pub type ReadError = err::ReadError;
389
390/// Deprecated use [err::ReadError] instead or use the specific error type returned by operation you are using.
391#[cfg(feature = "std")]
392#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
393#[deprecated(since = "0.14.0", note = "Please use the type err::Field instead.")]
394pub type ErrorField = err::ValueType;