diff --git a/README.md b/README.md index 371c5dc1..52f1ce0f 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Etherparse is intended to provide the basic network parsing functions that allow Some key points are: -* It is completly written in Rust and thoroughly tested. +* It is completely written in Rust and thoroughly tested. * Special attention has been paid to not use allocations or syscalls. * The package is still in development and can & will still change. * The current focus of development is on the most popular protocols in the internet & transport layer. @@ -40,7 +40,7 @@ Some key points are: Etherparse gives you two options for parsing network packages automatically: ### Slicing the packet -Here the different components in a packet are seperated without parsing all their fields. For each header a slice is generated that allows access to the fields of a header. +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. ```rust match SlicedPacket::from_ethernet(&packet) { Err(value) => println!("Err {:?}", value), @@ -67,7 +67,7 @@ In case you want to parse cut off packets (e.g. packets returned in in ICMP mess * [`LaxSlicedPacket::from_ip`](https://docs.rs/etherparse/~0/etherparse/struct.LaxSlicedPacket.html#method.from_ip) for parsing from an IPv4 or IPv6 downwards ### Deserializing all headers into structs -This option deserializes all known headers and transferes their contents to header structs. +This option deserializes all known headers and transfers their contents to header structs. ```rust match PacketHeaders::from_ethernet_slice(&packet) { Err(value) => println!("Err {:?}", value), @@ -108,8 +108,8 @@ It is also possible to only slice one packet layer: * [`Icmpv6Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Icmpv6Slice.html#method.from_slice) The resulting data types allow access to both the header(s) and the payload of the layer -and will automatially limit the length of payload if the layer has a length field limiting the -paylod (e.g. the payload of IPv6 packets will be limited by the "payload length" field in +and will automatically limit the length of payload if the layer has a length field limiting the +payload (e.g. the payload of IPv6 packets will be limited by the "payload length" field in an IPv6 header). ### Manually slicing & parsing only headers @@ -162,10 +162,10 @@ let builder = PacketBuilder:: ethernet2([1,2,3,4,5,6], //source mac [7,8,9,10,11,12]) //destination mac .ipv4([192,168,1,1], //source ip - [192,168,1,2], //desitination ip + [192,168,1,2], //destination ip 20) //time to life .udp(21, //source port - 1234); //desitnation port + 1234); //destination port //payload of the udp packet let payload = [1,2,3,4,5,6,7,8]; @@ -181,10 +181,10 @@ builder.write(&mut result, &payload).unwrap(); There is also an [example for TCP packets](etherparse/examples/write_tcp.rs) available. -Check out the [PacketBuilder documentation](https://docs.rs/etherparse/~0/etherparse/struct.PacketBuilder.html) for more informations. +Check out the [PacketBuilder documentation](https://docs.rs/etherparse/~0/etherparse/struct.PacketBuilder.html) for more information. -### Manually serialising each header -Alternativly it is possible to manually build a packet ([example](etherparse/examples/write_ipv4_udp.rs)). Generally each struct representing a header has a "write" method that allows it to be serialized. These write methods sometimes automatically calculate checksums and fill them in. In case this is unwanted behavior (e.g. if you want to generate a packet with an invalid checksum), it is also possible to call a "write_raw" method that will simply serialize the data without doing checksum calculations. +### Manually serializing each header +Alternatively it is possible to manually build a packet ([example](etherparse/examples/write_ipv4_udp.rs)). Generally each struct representing a header has a "write" method that allows it to be serialized. These write methods sometimes automatically calculate checksums and fill them in. In case this is unwanted behavior (e.g. if you want to generate a packet with an invalid checksum), it is also possible to call a "write_raw" method that will simply serialize the data without doing checksum calculations. Read the documentations of the different methods for a more details: diff --git a/changelog.md b/changelog.md index 6cd4cad3..6e9668dc 100644 --- a/changelog.md +++ b/changelog.md @@ -2,23 +2,47 @@ ## 0.14.0 +### Highlights + +* `SlicedPacket` & `PacketHeaders` now use the length fields in the headers to determine the payload length. +* The payload(s) in `SlicedPacket` now can be accessed via the layer slices (e.g. `link.unwrap().payload()`). +* Added `LaxSlicedPacket` & `LaxPacketHeaders` to allow for parsing of packets without length checks & other inconsistency checks present in `SlicedPacket` & `PacketHeaders`. +* `SlicedPacket.ip` & `PacketHeaders.ip` have been renamed to `SlicedPacket.net` & `PacketHeaders.net` +* Added `no_std` support. +* Errors are now more fine granular (in case you want a general error type you can convert all errors via `into` & `from` into `err::FromSliceError` or `err::ReadError`). +* Added `to_bytes()` methods to most header types. +* Added slice types which contain both the header(s) and payload (e.g. `IpSlice`, `UdpSlice`). +* Added payload types (e.g. `IpPayloadSlice`, `EtherPayloadSlice`) which contain the slice & information about the payload type (e.g. the IpNumber in case of an `IpPayloadSlice`). + +### What happened? + +This version took more then a year to complete. Which for sure was not my plan when starting out. + +I started out trying to implement correct handing of "payload lengths" (aka actually using the length fields in headers to determine the payload). This was needed, as without it, incorrect data would sometimes creep into the payload of and IP packet (see https://github.com/JulianSchmid/etherparse/issues/35 ). But this "simple" feature triggered a chain reaction of changes that required me to re-architect big parts of the crate. Specifically the error types were an major issue, which I did not forsee costing so much time and at some time. + +But no matter, now it is done. Sadly there are quiet some breaking changes, but I think the crate is now in a better position for future changes & behaves correcter then in the past. There are also quiet a lot of quality of life changes. + ### New * Added non-allocating `to_bytes()` methods that return `arrayvec::ArrayVec` to the following headers: * `Ipv4Header` - * TODO Add to all headers that have write methods +* Added `LaxSlicedPacket` & `LaxPacketHeaders` to allow for parsing of packets without length checks & other inconsistency checks present in `SlicedPacket` & `PacketHeaders`. +* `no_std` Support was added. To enable use etherparse without default features: `etherparse = { version = "0.14", default-features = false }` * Added `LEN` or `MIN_LEN` & `MAX_LEN` constants to all headers & packets. * Added `InternetSlice::source_addr` & `InternetSlice::destination_addr` to get the source & destination as `std::net::IpAddr` (thanks to @nagy) ### Changes in Behavior * `SlicedPacket` & `PacketHeaders` now also verify the total_length and payload length fields present in the IPv4 & IPv6 header. This means the `*from_slice*` methods newly throw an error not enough data is present and also newly limit the resulting payload size. +* The payload(s) in `SlicedPacket` now can be accessed via the layer fields (e.g. `link.unwrap().payload()`). +* The payload in `PacketHeaders` now is an enum that indicates from which layer the payload came. * Removed `ReadError::Ipv6TooManyHeaderExtensions` error when calling `Ipv6Header::skip_all_header_extensions` and `Ipv6Header::skip_all_header_extensions_in_slice`. * The slice returned by `IpHeader::from_slice`is now the payload of the IP packet (determined by the length specified in the IP header). Previously whatever was left over from the input slice after parsing the IP header and extensions was returned. Now the slice length is limited based on the "payload length" field (IPv6) or "total length" field IPv4. * `Ipv4Header::from_slice` no longer verifies that the `total_len` has enough data to contain the header itself. This check is done when the complete packet is parsed. The check was removed as the `total_len` is sometimes set at a later stage (e.g. in the kernel) in some systems and I would still like to enable people to at least decode the header even if the total length was not yet set. ### Breaking Changes: +* `ip` as been renamed to `net` in `SlicedPacket` and `PacketHeaders` * `packet_filter` has been removed * Refactored error types so functions & methods (mostly) only return error types that they can cause. * Removed `SerializedSize` trait and deprecated `SERIALIZED_SIZE`. Newly added constants `Header::LEN`, `Header::MIN_LEN` & `Header::MAX_LEN` to the headers as an replacement. @@ -30,7 +54,7 @@ * `Ipv4Header.fragments_offset` renamed to `Ipv4Header.fragment_offset`. * `SingleVlanHeader.vlan_identifier` renamed to `SingleVlanHeader.vlan_id`. * Type of `vlan_id` in `SingleVlanHeader` changed from `u16` to `VlanId`. -* Moved options of `Ipv4Header` and `TcpHeader` into seperate structs and made all fields in `Ipv4Header` & `TcpHeader` public for easier default initialisation. +* Moved options of `Ipv4Header` and `TcpHeader` into separate structs and made all fields in `Ipv4Header` & `TcpHeader` public for easier default initialization. ### Bugfixes @@ -39,7 +63,7 @@ * `Ipv6Header::skip_header_extension_in_slice` * `Ipv6Header::skip_all_header_extensions_in_slice` -* Previously the manual `core::fmt::Debug` implementations for some types were not correctly inserting newlines & identation when `{:#?}` was used for debug printing. This has been corrected for the following types: +* Previously the manual `core::fmt::Debug` implementations for some types were not correctly inserting newlines & indentation when `{:#?}` was used for debug printing. This has been corrected for the following types: * `Ipv4Header` * `IpAuthHeader` * `Ipv6RawExtHeader` @@ -47,7 +71,7 @@ ### Deprecations / Renames: * The following types have been renamed (alias with the old name exist for backwards compatibility but will trigger a deprecation warning): - * `InternetSlice` to `IpSlice` + * `InternetSlice` to `NetSlice` & `IpSlice` * `IpAuthenticationHeader` to `IpAuthHeader` * `IpAuthenticationHeaderSlice` to `IpAuthHeaderSlice` * `Ipv6RawExtensionHeader` to `Ipv6RawExtHeader` @@ -55,8 +79,9 @@ ### Internal Changes: -* Seperated proptest generators into seperate library `etherparse_proptest_generators` -* TODO Split modules up into one file per struct/enum and moved tests there +* Separated proptest generators into separate library `etherparse_proptest_generators` +* Split modules up into one file per struct/enum and moved tests there +* Applied rust fmt ## 0.13.0 diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index a90b85eb..9cc0dbd6 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -24,7 +24,7 @@ //! //! Some key points are: //! -//! * It is completly written in Rust and thoroughly tested. +//! * It is completely written in Rust and thoroughly tested. //! * Special attention has been paid to not use allocations or syscalls. //! * The package is still in development and can & will still change. //! * The current focus of development is on the most popular protocols in the internet & transport layer. @@ -33,7 +33,7 @@ //! Etherparse gives you two options for parsing network packages automatically: //! //! ## Slicing the packet -//! Here the different components in a packet are seperated without parsing all their fields. For each header a slice is generated that allows access to the fields of a header. +//! 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. //! ``` //! # use etherparse::{SlicedPacket, PacketBuilder}; //! # let builder = PacketBuilder:: @@ -43,7 +43,7 @@ //! # [192,168,1,2], //destination ip //! # 20) //time to life //! # .udp(21, //source port -//! # 1234); //desitnation port +//! # 1234); //destination port //! # //payload of the udp packet //! # let payload = [1,2,3,4,5,6,7,8]; //! # //get some memory to store the serialized data @@ -76,7 +76,7 @@ //! //! ## Deserializing all headers into structs //! -//! This option deserializes all known headers and transferes their contents to header structs. +//! This option deserializes all known headers and transfers their contents to header structs. //! ```rust //! # use etherparse::{PacketHeaders, PacketBuilder}; //! # let builder = PacketBuilder:: @@ -86,7 +86,7 @@ //! # [192,168,1,2], //destination ip //! # 20) //time to life //! # .udp(21, //source port -//! # 1234); //desitnation port +//! # 1234); //destination port //! # //payload of the udp packet //! # let payload = [1,2,3,4,5,6,7,8]; //! # //get some memory to store the serialized data @@ -132,8 +132,8 @@ //! * [`Icmpv6Slice::from_slice`] //! //! The resulting data types allow access to both the header(s) and the payload of the layer -//! and will automatially limit the length of payload if the layer has a length field limiting the -//! paylod (e.g. the payload of IPv6 packets will be limited by the "payload length" field in +//! and will automatically limit the length of payload if the layer has a length field limiting the +//! payload (e.g. the payload of IPv6 packets will be limited by the "payload length" field in //! an IPv6 header). //! //! ## Manually slicing & parsing only headers @@ -186,10 +186,10 @@ //! ethernet2([1,2,3,4,5,6], //source mac //! [7,8,9,10,11,12]) //destination mac //! .ipv4([192,168,1,1], //source ip -//! [192,168,1,2], //desitination ip +//! [192,168,1,2], //destination ip //! 20) //time to life //! .udp(21, //source port -//! 1234); //desitnation port +//! 1234); //destination port //! //! //payload of the udp packet //! let payload = [1,2,3,4,5,6,7,8]; @@ -205,11 +205,11 @@ //! //! There is also an [example for TCP packets](https://github.com/JulianSchmid/etherparse/blob/0.14.0/examples/write_tcp.rs) available. //! -//! Check out the [PacketBuilder documentation](struct.PacketBuilder.html) for more informations. +//! Check out the [PacketBuilder documentation](struct.PacketBuilder.html) for more information. //! -//! ## Manually serialising each header +//! ## Manually serializing each header //! -//! Alternativly it is possible to manually build a packet +//! Alternatively it is possible to manually build a packet //! ([example](https://github.com/JulianSchmid/etherparse/blob/0.14.0/examples/write_ipv4_udp.rs)). //! Generally each struct representing a header has a "write" method that allows it to be //! serialized. These write methods sometimes automatically calculate checksums and fill them