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