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