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