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