diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2fcb8b8d..564f6378 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -114,6 +114,36 @@ jobs: use-cross: true command: test args: --target ${{ matrix.target }} --no-default-features + + - name: cargo build serde + if: matrix.target == '' + uses: actions-rs/cargo@v1 + with: + command: build + args: --features serde + + - name: cross build serde + if: matrix.target != '' + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --target ${{ matrix.target }} --features serde + + - name: cargo test serde + if: matrix.target == '' + uses: actions-rs/cargo@v1 + with: + command: test + args: --features serde + + - name: cross test serde + if: matrix.target != '' + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: test + args: --target ${{ matrix.target }} --features serde no_std_build: name: no_std build @@ -129,4 +159,4 @@ jobs: toolchain: stable target: x86_64-unknown-none override: true - - run: cargo build --target x86_64-unknown-none + - run: cargo build --target x86_64-unknown-none \ No newline at end of file diff --git a/etherparse/Cargo.toml b/etherparse/Cargo.toml index 64a338d0..d589ce3c 100644 --- a/etherparse/Cargo.toml +++ b/etherparse/Cargo.toml @@ -19,11 +19,14 @@ exclude = [ ] [features] -default = ["std"] -std = ["arrayvec/std"] +default = ["std", "serde"] +std = [] +serde = ["dep:serde", "dep:serde_arrays"] [dependencies] arrayvec = { version = "0.7.2", default-features = false } +serde = { version = "1.0", optional = true, features = ["derive"] } +serde_arrays = { version = "0.1", optional = true } [dev-dependencies] proptest = "1.4.0" diff --git a/etherparse/src/len_source.rs b/etherparse/src/len_source.rs index 45d00393..9eed5157 100644 --- a/etherparse/src/len_source.rs +++ b/etherparse/src/len_source.rs @@ -1,5 +1,6 @@ /// Sources of length limiting values (e.g. "ipv6 payload length field"). #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LenSource { /// Limiting length was the slice length (we don't know what determined /// that one originally). diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 2da16e7e..9884e05a 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -403,9 +403,19 @@ pub use crate::packet_builder::*; mod packet_headers; pub use crate::packet_headers::*; +#[cfg(feature = "std")] +mod packet; +#[cfg(feature = "std")] +pub use crate::packet::*; + mod payload_slice; pub use crate::payload_slice::*; +#[cfg(feature = "std")] +mod payload; +#[cfg(feature = "std")] +pub use crate::payload::*; + mod sliced_packet; pub use crate::sliced_packet::*; diff --git a/etherparse/src/link/arp_hardware_id.rs b/etherparse/src/link/arp_hardware_id.rs index 2f89ce48..e0c81e6e 100644 --- a/etherparse/src/link/arp_hardware_id.rs +++ b/etherparse/src/link/arp_hardware_id.rs @@ -20,6 +20,7 @@ /// #[derive(Clone, Copy, Eq, PartialEq, Default, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ArpHardwareId(pub u16); impl ArpHardwareId { diff --git a/etherparse/src/link/double_vlan_header.rs b/etherparse/src/link/double_vlan_header.rs index dd2aed11..41ec04b6 100644 --- a/etherparse/src/link/double_vlan_header.rs +++ b/etherparse/src/link/double_vlan_header.rs @@ -2,6 +2,7 @@ use crate::*; /// IEEE 802.1Q double VLAN Tagging Header #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DoubleVlanHeader { /// The outer vlan tagging header pub outer: SingleVlanHeader, diff --git a/etherparse/src/link/ether_payload.rs b/etherparse/src/link/ether_payload.rs new file mode 100644 index 00000000..5c2feb62 --- /dev/null +++ b/etherparse/src/link/ether_payload.rs @@ -0,0 +1,22 @@ +use std::vec::Vec; + +use crate::{EtherPayloadSlice, EtherType}; + +/// Payload of an IP packet. Owned version of [`EtherPayloadSlice`]. +#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct EtherPayload { + /// Identifying content of the payload. + pub ether_type: EtherType, + /// Payload + pub payload: Vec, +} + +impl<'a> From> for EtherPayload { + fn from(slice: EtherPayloadSlice<'a>) -> Self { + Self { + ether_type: slice.ether_type, + payload: slice.payload.to_vec(), + } + } +} diff --git a/etherparse/src/link/ether_payload_slice.rs b/etherparse/src/link/ether_payload_slice.rs index 0a19e81a..1bf7fb77 100644 --- a/etherparse/src/link/ether_payload_slice.rs +++ b/etherparse/src/link/ether_payload_slice.rs @@ -2,6 +2,7 @@ use crate::*; /// Payload of an IP packet. #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EtherPayloadSlice<'a> { /// Identifying content of the payload. pub ether_type: EtherType, diff --git a/etherparse/src/link/ether_type_impl.rs b/etherparse/src/link/ether_type_impl.rs index 9cf65188..189e2f18 100644 --- a/etherparse/src/link/ether_type_impl.rs +++ b/etherparse/src/link/ether_type_impl.rs @@ -28,6 +28,7 @@ /// ``` /// #[derive(Default, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EtherType(pub u16); impl EtherType { diff --git a/etherparse/src/link/ethernet2_header.rs b/etherparse/src/link/ethernet2_header.rs index 6334068f..f26b8f1c 100644 --- a/etherparse/src/link/ethernet2_header.rs +++ b/etherparse/src/link/ethernet2_header.rs @@ -2,6 +2,7 @@ use crate::{err::Layer, err::SliceWriteSpaceError, *}; /// Ethernet II header. #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ethernet2Header { /// Source MAC Address pub source: [u8; 6], diff --git a/etherparse/src/link/link_header.rs b/etherparse/src/link/link_header.rs index 1c5caa2f..7527d685 100644 --- a/etherparse/src/link/link_header.rs +++ b/etherparse/src/link/link_header.rs @@ -2,6 +2,7 @@ use crate::{Ethernet2Header, LinuxSllHeader}; /// The possible headers on the link layer #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LinkHeader { LinuxSll(LinuxSllHeader), Ethernet2(Ethernet2Header), diff --git a/etherparse/src/link/linux_nonstandard_ether_type.rs b/etherparse/src/link/linux_nonstandard_ether_type.rs index 24f151c2..c9aee8a3 100644 --- a/etherparse/src/link/linux_nonstandard_ether_type.rs +++ b/etherparse/src/link/linux_nonstandard_ether_type.rs @@ -16,6 +16,7 @@ /// assert_eq!(0x0001, num); /// ``` #[derive(Clone, Copy, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LinuxNonstandardEtherType(pub(crate) u16); impl LinuxNonstandardEtherType { diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index ec1a1ba9..6782b66c 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -2,6 +2,7 @@ use crate::{err, ArpHardwareId, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSl /// Linux Cooked Capture v1 (SLL) Header #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LinuxSllHeader { /// Type of the captured packet pub packet_type: LinuxSllPacketType, diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs index 78c62a3c..81e66d4e 100644 --- a/etherparse/src/link/linux_sll_packet_type.rs +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -20,6 +20,7 @@ use crate::err::{self}; /// assert_eq!(1, num); /// ``` #[derive(Clone, Copy, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LinuxSllPacketType(u16); impl LinuxSllPacketType { diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs index da259b6e..9840d696 100644 --- a/etherparse/src/link/linux_sll_protocol_type.rs +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -20,6 +20,7 @@ use crate::{err, ArpHardwareId, EtherType, LinuxNonstandardEtherType}; /// assert_eq!(0x0001, num); /// ``` #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LinuxSllProtocolType { /// The protocol type should be ignored Ignored(u16), diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index fab5b803..848f62d6 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -23,3 +23,6 @@ pub mod vlan_header; pub mod vlan_id; pub mod vlan_pcp; pub mod vlan_slice; + +#[cfg(feature = "std")] +pub mod ether_payload; diff --git a/etherparse/src/link/single_vlan_header.rs b/etherparse/src/link/single_vlan_header.rs index a8d9ce08..9ba8ef6d 100644 --- a/etherparse/src/link/single_vlan_header.rs +++ b/etherparse/src/link/single_vlan_header.rs @@ -2,6 +2,7 @@ use crate::*; /// IEEE 802.1Q VLAN Tagging Header #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SingleVlanHeader { /// A 3 bit number which refers to the IEEE 802.1p class of service and maps to the frame priority level. pub pcp: VlanPcp, diff --git a/etherparse/src/link/vlan_header.rs b/etherparse/src/link/vlan_header.rs index f01a1974..76151b6a 100644 --- a/etherparse/src/link/vlan_header.rs +++ b/etherparse/src/link/vlan_header.rs @@ -2,6 +2,7 @@ use crate::*; /// IEEE 802.1Q VLAN Tagging Header (can be single or double tagged). #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum VlanHeader { /// IEEE 802.1Q VLAN Tagging Header Single(SingleVlanHeader), diff --git a/etherparse/src/link/vlan_id.rs b/etherparse/src/link/vlan_id.rs index d5d5bfd5..412504bd 100644 --- a/etherparse/src/link/vlan_id.rs +++ b/etherparse/src/link/vlan_id.rs @@ -3,6 +3,7 @@ use crate::err::ValueTooBigError; /// 12 bit unsigned integer containing the "VLAN identifier" (present /// in the [`crate::SingleVlanHeader`]). #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VlanId(u16); impl VlanId { diff --git a/etherparse/src/link/vlan_pcp.rs b/etherparse/src/link/vlan_pcp.rs index 7759bdb0..2ba6ca8b 100644 --- a/etherparse/src/link/vlan_pcp.rs +++ b/etherparse/src/link/vlan_pcp.rs @@ -6,6 +6,7 @@ use crate::err::ValueTooBigError; /// Refers to the IEEE 802.1p class of service and maps to the /// frame priority level. #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VlanPcp(u8); impl VlanPcp { diff --git a/etherparse/src/net/ip_auth_header.rs b/etherparse/src/net/ip_auth_header.rs index 2d406a1a..1b2dbbe0 100644 --- a/etherparse/src/net/ip_auth_header.rs +++ b/etherparse/src/net/ip_auth_header.rs @@ -13,6 +13,7 @@ pub type IpAuthenticationHeader = IpAuthHeader; /// IP Authentication Header (rfc4302) #[derive(Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IpAuthHeader { /// IP protocol number specifying the next header or transport layer protocol. /// @@ -28,6 +29,7 @@ pub struct IpAuthHeader { raw_icv_len: u8, /// Buffer containing the "Encoded Integrity Check Value-ICV" (variable). /// The length of the used data can be set via the `variable` (must be a multiple of 4 bytes). + #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))] raw_icv_buffer: [u8; 0xfe * 4], } diff --git a/etherparse/src/net/ip_frag_offset.rs b/etherparse/src/net/ip_frag_offset.rs index 8370baf8..2e30c080 100644 --- a/etherparse/src/net/ip_frag_offset.rs +++ b/etherparse/src/net/ip_frag_offset.rs @@ -53,6 +53,7 @@ use crate::err::ValueTooBigError; /// } /// ``` #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IpFragOffset(u16); impl IpFragOffset { diff --git a/etherparse/src/net/ip_number_impl.rs b/etherparse/src/net/ip_number_impl.rs index 25502736..9987cf0f 100644 --- a/etherparse/src/net/ip_number_impl.rs +++ b/etherparse/src/net/ip_number_impl.rs @@ -44,6 +44,7 @@ pub type IpTrafficClass = IpNumber; /// The list original values were copied from /// #[derive(PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IpNumber(pub u8); impl IpNumber { diff --git a/etherparse/src/net/ip_payload.rs b/etherparse/src/net/ip_payload.rs new file mode 100644 index 00000000..630218ca --- /dev/null +++ b/etherparse/src/net/ip_payload.rs @@ -0,0 +1,36 @@ +use std::vec::Vec; + +use crate::{IpNumber, IpPayloadSlice, LenSource}; + +/// Payload of an IP packet. Owned version of [`IpPayloadSlice`]. +#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct IpPayload { + /// Identifying content of the payload. + pub ip_number: IpNumber, + + /// True if the payload is not complete and has been fragmented. + /// + /// This can occur if the IPv4 incdicates that the payload + /// has been fragmented or if there is an IPv6 fragmentation + /// header indicating that the payload has been fragmented. + pub fragmented: bool, + + /// Length field that was used to determine the length + /// of the payload (e.g. IPv6 "payload_length" field). + pub len_source: LenSource, + + /// Payload + pub payload: Vec, +} + +impl<'a> From> for IpPayload { + fn from(slice: IpPayloadSlice<'a>) -> Self { + Self { + ip_number: slice.ip_number, + fragmented: slice.fragmented, + len_source: slice.len_source, + payload: slice.payload.to_vec(), + } + } +} diff --git a/etherparse/src/net/ip_payload_slice.rs b/etherparse/src/net/ip_payload_slice.rs index 91456e9d..65fd56c4 100644 --- a/etherparse/src/net/ip_payload_slice.rs +++ b/etherparse/src/net/ip_payload_slice.rs @@ -2,6 +2,7 @@ use crate::*; /// Payload of an IP packet. #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IpPayloadSlice<'a> { /// Identifying content of the payload. pub ip_number: IpNumber, diff --git a/etherparse/src/net/ipv4_dscp.rs b/etherparse/src/net/ipv4_dscp.rs index 9498b342..53d98dfd 100644 --- a/etherparse/src/net/ipv4_dscp.rs +++ b/etherparse/src/net/ipv4_dscp.rs @@ -3,6 +3,7 @@ use crate::err::ValueTooBigError; /// 6 bit unsigned integer containing the "Differentiated Services /// Code Point" (present in the [`crate::Ipv4Header`]). #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv4Dscp(u8); impl Ipv4Dscp { diff --git a/etherparse/src/net/ipv4_ecn.rs b/etherparse/src/net/ipv4_ecn.rs index d9a5e5df..a9bb6643 100644 --- a/etherparse/src/net/ipv4_ecn.rs +++ b/etherparse/src/net/ipv4_ecn.rs @@ -3,6 +3,7 @@ use crate::err::ValueTooBigError; /// 2 bit unsigned integer containing the "Explicit Congestion /// Notification" (present in the [`crate::Ipv4Header`]). #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv4Ecn(u8); impl Ipv4Ecn { diff --git a/etherparse/src/net/ipv4_exts.rs b/etherparse/src/net/ipv4_exts.rs index 1c9ff7e6..138a870e 100644 --- a/etherparse/src/net/ipv4_exts.rs +++ b/etherparse/src/net/ipv4_exts.rs @@ -8,6 +8,7 @@ use crate::{err::ipv4_exts::ExtsWalkError, *}; /// Currently not supported: /// - Encapsulating Security Payload Header (ESP) #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv4Extensions { pub auth: Option, } diff --git a/etherparse/src/net/ipv4_header.rs b/etherparse/src/net/ipv4_header.rs index b29e7697..a1c01213 100644 --- a/etherparse/src/net/ipv4_header.rs +++ b/etherparse/src/net/ipv4_header.rs @@ -33,6 +33,7 @@ use arrayvec::ArrayVec; /// assert_eq!(slice_rest, &[]); /// ``` #[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv4Header { /// Differentiated Services Code Point pub dscp: Ipv4Dscp, diff --git a/etherparse/src/net/ipv4_options.rs b/etherparse/src/net/ipv4_options.rs index f741a072..8649ef84 100644 --- a/etherparse/src/net/ipv4_options.rs +++ b/etherparse/src/net/ipv4_options.rs @@ -35,8 +35,10 @@ use core::borrow::{Borrow, BorrowMut}; /// } /// ``` #[derive(Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv4Options { pub(crate) len: u8, + #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))] pub(crate) buf: [u8; 40], } diff --git a/etherparse/src/net/ipv6_exts.rs b/etherparse/src/net/ipv6_exts.rs index afbd104d..1cadc927 100644 --- a/etherparse/src/net/ipv6_exts.rs +++ b/etherparse/src/net/ipv6_exts.rs @@ -21,6 +21,7 @@ use crate::{ /// * IP Mobility /// * Site Multihoming by IPv6 Intermediation (SHIM6) #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6Extensions { pub hop_by_hop_options: Option, pub destination_options: Option, diff --git a/etherparse/src/net/ipv6_flow_label.rs b/etherparse/src/net/ipv6_flow_label.rs index 7b956173..62e062fa 100644 --- a/etherparse/src/net/ipv6_flow_label.rs +++ b/etherparse/src/net/ipv6_flow_label.rs @@ -49,6 +49,7 @@ use crate::err::ValueTooBigError; /// } /// ``` #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6FlowLabel(u32); impl Ipv6FlowLabel { diff --git a/etherparse/src/net/ipv6_fragment_header.rs b/etherparse/src/net/ipv6_fragment_header.rs index 4ab7486d..6426267b 100644 --- a/etherparse/src/net/ipv6_fragment_header.rs +++ b/etherparse/src/net/ipv6_fragment_header.rs @@ -2,6 +2,7 @@ use super::super::*; /// IPv6 fragment header. #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6FragmentHeader { /// IP protocol number specifying the next header or transport layer protocol. /// diff --git a/etherparse/src/net/ipv6_header.rs b/etherparse/src/net/ipv6_header.rs index 7676466c..a3e5a0ca 100644 --- a/etherparse/src/net/ipv6_header.rs +++ b/etherparse/src/net/ipv6_header.rs @@ -2,6 +2,7 @@ use crate::{err::ValueTooBigError, *}; /// IPv6 header according to rfc8200. #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6Header { pub traffic_class: u8, /// If non 0 serves as a hint to router and switches with multiple outbound paths that these packets should stay on the same path, so that they will not be reordered. diff --git a/etherparse/src/net/ipv6_raw_ext_header.rs b/etherparse/src/net/ipv6_raw_ext_header.rs index 2a664ac1..ff37a8a7 100644 --- a/etherparse/src/net/ipv6_raw_ext_header.rs +++ b/etherparse/src/net/ipv6_raw_ext_header.rs @@ -25,6 +25,7 @@ pub type Ipv6RawExtensionHeader = Ipv6RawExtHeader; /// * Host Identity Protocol /// * Shim6 Protocol #[derive(Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6RawExtHeader { /// IP protocol number specifying the next header or transport layer protocol. /// @@ -33,6 +34,7 @@ pub struct Ipv6RawExtHeader { /// Length of the extension header in 8 octets (minus the first 8 octets). header_length: u8, //// The data contained in the extension header (excluding next_header & hdr length). + #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))] payload_buffer: [u8; 0xff * 8 + 6], } diff --git a/etherparse/src/net/ipv6_routing_exts.rs b/etherparse/src/net/ipv6_routing_exts.rs index b3b4aa91..b2fd27e6 100644 --- a/etherparse/src/net/ipv6_routing_exts.rs +++ b/etherparse/src/net/ipv6_routing_exts.rs @@ -3,6 +3,7 @@ use crate::*; /// In case a route header is present it is also possible /// to attach a "final destination" header. #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ipv6RoutingExtensions { pub routing: Ipv6RawExtHeader, pub final_destination_options: Option, diff --git a/etherparse/src/net/mod.rs b/etherparse/src/net/mod.rs index cee996fc..7a37322e 100644 --- a/etherparse/src/net/mod.rs +++ b/etherparse/src/net/mod.rs @@ -16,6 +16,11 @@ pub use ip_number_impl::*; mod ip_payload_slice; pub use ip_payload_slice::*; +#[cfg(feature = "std")] +mod ip_payload; +#[cfg(feature = "std")] +pub use ip_payload::*; + mod ip_slice; pub use ip_slice::*; diff --git a/etherparse/src/net/net_headers.rs b/etherparse/src/net/net_headers.rs index f2af1f44..707b800e 100644 --- a/etherparse/src/net/net_headers.rs +++ b/etherparse/src/net/net_headers.rs @@ -7,6 +7,7 @@ pub type IpHeader = NetHeaders; /// Headers on the network layer (e.g. IP, ARP, ...). #[derive(Clone, Debug, Eq, PartialEq)] #[allow(clippy::large_enum_variant)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum NetHeaders { /// IPv4 header & extension headers. Ipv4(Ipv4Header, Ipv4Extensions), diff --git a/etherparse/src/packet.rs b/etherparse/src/packet.rs new file mode 100644 index 00000000..2444f0f9 --- /dev/null +++ b/etherparse/src/packet.rs @@ -0,0 +1,29 @@ +use crate::{LinkHeader, NetHeaders, PacketHeaders, Payload, TransportHeader, VlanHeader}; + +/// Owned version of [`crate::SlicedPacket`]. +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Packet { + /// Ethernet II header if present. + pub link: Option, + /// Single or double vlan headers if present. + pub vlan: Option, + /// IPv4 or IPv6 header and IP extension headers if present. + pub net: Option, + /// TCP or UDP header if present. + pub transport: Option, + /// Payload of the last parsed layer. + pub payload: Payload, +} + +impl From> for Packet { + fn from(headers: PacketHeaders) -> Self { + Self { + link: headers.link, + vlan: headers.vlan, + net: headers.net, + transport: headers.transport, + payload: headers.payload.into(), + } + } +} diff --git a/etherparse/src/packet_headers.rs b/etherparse/src/packet_headers.rs index a14f805f..65b28b0f 100644 --- a/etherparse/src/packet_headers.rs +++ b/etherparse/src/packet_headers.rs @@ -13,6 +13,8 @@ use super::*; /// depending on your starting header to parse the headers in a slice and get this /// struct as a result. #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(bound(deserialize = "'de: 'a")))] pub struct PacketHeaders<'a> { /// Ethernet II header if present. pub link: Option, diff --git a/etherparse/src/payload.rs b/etherparse/src/payload.rs new file mode 100644 index 00000000..5c34ba69 --- /dev/null +++ b/etherparse/src/payload.rs @@ -0,0 +1,62 @@ +use std::vec::Vec; + +use crate::{link::ether_payload::EtherPayload, IpPayload, PayloadSlice}; + +/// Payload together with an identifier the type of content. Owned version of [`PayloadSlice`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Payload { + /// Payload with it's type identified by an ether type number + /// (e.g. after an ethernet II or vlan header). + Ether(EtherPayload), + /// Payload with is's type identified by an ip number (e.g. + /// after an IP header or after an) + Ip(IpPayload), + /// UDP payload. + Udp(Vec), + /// TCP payload. + Tcp(Vec), + /// Payload part of an ICMP V4 message. Check [`crate::Icmpv4Type`] + /// for a description what will be part of the payload. + Icmpv4(Vec), + /// Payload part of an ICMP V4 message. Check [`crate::Icmpv6Type`] + /// for a description what will be part of the payload. + Icmpv6(Vec), +} + +impl<'a> From> for Payload { + fn from(slice: PayloadSlice<'a>) -> Self { + match slice { + PayloadSlice::Ether(s) => Self::Ether(s.into()), + PayloadSlice::Ip(s) => Self::Ip(s.into()), + PayloadSlice::Udp(s) => Self::Udp(s.to_vec()), + PayloadSlice::Tcp(s) => Self::Tcp(s.to_vec()), + PayloadSlice::Icmpv4(s) => Self::Icmpv4(s.to_vec()), + PayloadSlice::Icmpv6(s) => Self::Icmpv6(s.to_vec()), + } + } +} + +impl Payload { + pub fn slice(&self) -> &[u8] { + match self { + Payload::Ether(s) => s.payload.as_slice(), + Payload::Ip(s) => s.payload.as_slice(), + Payload::Udp(s) => s, + Payload::Tcp(s) => s, + Payload::Icmpv4(s) => s, + Payload::Icmpv6(s) => s, + } + } + + pub fn content(self) -> Vec { + match self { + Payload::Ether(s) => s.payload, + Payload::Ip(s) => s.payload, + Payload::Udp(s) => s, + Payload::Tcp(s) => s, + Payload::Icmpv4(s) => s, + Payload::Icmpv6(s) => s, + } + } +} diff --git a/etherparse/src/payload_slice.rs b/etherparse/src/payload_slice.rs index 3715e542..e01693a7 100644 --- a/etherparse/src/payload_slice.rs +++ b/etherparse/src/payload_slice.rs @@ -2,6 +2,7 @@ use crate::*; /// Payload together with an identifier the type of content. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum PayloadSlice<'a> { /// Payload with it's type identified by an ether type number /// (e.g. after an ethernet II or vlan header). diff --git a/etherparse/src/transport/icmp_echo_header.rs b/etherparse/src/transport/icmp_echo_header.rs index ba139a9b..848c7108 100644 --- a/etherparse/src/transport/icmp_echo_header.rs +++ b/etherparse/src/transport/icmp_echo_header.rs @@ -8,6 +8,7 @@ /// originating Echo Requests and receiving Echo Replies, for diagnostic /// purposes. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IcmpEchoHeader { /// An identifier to aid in matching Echo Replies to Echo Requests. May be zero. pub id: u16, diff --git a/etherparse/src/transport/icmpv4/dest_unreachable_header.rs b/etherparse/src/transport/icmpv4/dest_unreachable_header.rs index 3f5c10df..57b70c17 100644 --- a/etherparse/src/transport/icmpv4/dest_unreachable_header.rs +++ b/etherparse/src/transport/icmpv4/dest_unreachable_header.rs @@ -25,6 +25,7 @@ /// Codes 0, 1, 4, and 5 may be received from a gateway. Codes 2 and /// 3 may be received from a host. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum DestUnreachableHeader { /// Network unreachable error. Network, diff --git a/etherparse/src/transport/icmpv4/parameter_problem_header.rs b/etherparse/src/transport/icmpv4/parameter_problem_header.rs index 000efbd6..9da6a775 100644 --- a/etherparse/src/transport/icmpv4/parameter_problem_header.rs +++ b/etherparse/src/transport/icmpv4/parameter_problem_header.rs @@ -1,6 +1,7 @@ /// The header of an ICMPv4 Parameter Problems (contents up to /// the offending ip header). #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ParameterProblemHeader { /// Identifies the octet where an error was detected. /// diff --git a/etherparse/src/transport/icmpv4/redirect_code.rs b/etherparse/src/transport/icmpv4/redirect_code.rs index 487602b8..288690e8 100644 --- a/etherparse/src/transport/icmpv4/redirect_code.rs +++ b/etherparse/src/transport/icmpv4/redirect_code.rs @@ -1,5 +1,6 @@ /// Code value in an ICMPv4 Redirect message. #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RedirectCode { /// Redirect Datagram for the Network (or subnet) RedirectForNetwork = 0, diff --git a/etherparse/src/transport/icmpv4/redirect_header.rs b/etherparse/src/transport/icmpv4/redirect_header.rs index 86d9dc57..b3b03fd6 100644 --- a/etherparse/src/transport/icmpv4/redirect_header.rs +++ b/etherparse/src/transport/icmpv4/redirect_header.rs @@ -1,6 +1,7 @@ use super::*; #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RedirectHeader { pub code: RedirectCode, pub gateway_internet_address: [u8; 4], diff --git a/etherparse/src/transport/icmpv4/time_exceeded_code.rs b/etherparse/src/transport/icmpv4/time_exceeded_code.rs index f74fe5f1..baa6e7f6 100644 --- a/etherparse/src/transport/icmpv4/time_exceeded_code.rs +++ b/etherparse/src/transport/icmpv4/time_exceeded_code.rs @@ -2,6 +2,7 @@ use super::*; /// Code values for ICMPv4 time exceeded message. #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TimeExceededCode { /// Time-to-live exceeded in transit. TtlExceededInTransit = 0, diff --git a/etherparse/src/transport/icmpv4/timestamp_message.rs b/etherparse/src/transport/icmpv4/timestamp_message.rs index 047312d9..4ebba12a 100644 --- a/etherparse/src/transport/icmpv4/timestamp_message.rs +++ b/etherparse/src/transport/icmpv4/timestamp_message.rs @@ -1,5 +1,6 @@ /// A ICMPv4 timestamp or timestamp response message. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TimestampMessage { pub id: u16, pub seq: u16, diff --git a/etherparse/src/transport/icmpv4_header.rs b/etherparse/src/transport/icmpv4_header.rs index 6b24f1c0..2ed55b4d 100644 --- a/etherparse/src/transport/icmpv4_header.rs +++ b/etherparse/src/transport/icmpv4_header.rs @@ -7,6 +7,7 @@ use arrayvec::ArrayVec; /// and code. But usually the static sized elements are part /// of the header. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Icmpv4Header { /// Type & type specific values & code. pub icmp_type: Icmpv4Type, diff --git a/etherparse/src/transport/icmpv4_type.rs b/etherparse/src/transport/icmpv4_type.rs index 307814fe..b0efad01 100644 --- a/etherparse/src/transport/icmpv4_type.rs +++ b/etherparse/src/transport/icmpv4_type.rs @@ -2,6 +2,7 @@ use crate::*; /// Starting contents of an ICMPv4 packet without the checksum. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Icmpv4Type { /// In case of an unknown ICMP type and code combination is received the /// header elements are stored raw in this enum value. The `Unknown` value can diff --git a/etherparse/src/transport/icmpv6/dest_unreachable_code.rs b/etherparse/src/transport/icmpv6/dest_unreachable_code.rs index 4f72d1ba..d20069ac 100644 --- a/etherparse/src/transport/icmpv6/dest_unreachable_code.rs +++ b/etherparse/src/transport/icmpv6/dest_unreachable_code.rs @@ -11,6 +11,7 @@ use super::*; /// than congestion. (An ICMPv6 message MUST NOT be generated if a /// packet is dropped due to congestion.) #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum DestUnreachableCode { /// No route to destination NoRoute = 0, diff --git a/etherparse/src/transport/icmpv6/parameter_problem_code.rs b/etherparse/src/transport/icmpv6/parameter_problem_code.rs index 76164018..39161189 100644 --- a/etherparse/src/transport/icmpv6/parameter_problem_code.rs +++ b/etherparse/src/transport/icmpv6/parameter_problem_code.rs @@ -4,6 +4,7 @@ use super::*; /// /// Source: #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ParameterProblemCode { /// Erroneous header field encountered (from [RFC 4443](https://tools.ietf.org/html/rfc4443)) ErroneousHeaderField = 0, diff --git a/etherparse/src/transport/icmpv6/parameter_problem_header.rs b/etherparse/src/transport/icmpv6/parameter_problem_header.rs index c1896810..9dfd4d4f 100644 --- a/etherparse/src/transport/icmpv6/parameter_problem_header.rs +++ b/etherparse/src/transport/icmpv6/parameter_problem_header.rs @@ -2,6 +2,7 @@ use super::*; /// ICMPv6 parameter problem header. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ParameterProblemHeader { /// The code can offer additional informations about what kind of parameter /// problem caused the error. diff --git a/etherparse/src/transport/icmpv6/time_exceeded_code.rs b/etherparse/src/transport/icmpv6/time_exceeded_code.rs index 9f060304..a2bdcd75 100644 --- a/etherparse/src/transport/icmpv6/time_exceeded_code.rs +++ b/etherparse/src/transport/icmpv6/time_exceeded_code.rs @@ -2,6 +2,7 @@ use super::*; /// Code values for ICMPv6 time exceeded message. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TimeExceededCode { /// "hop limit exceeded in transit" HopLimitExceeded = 0, diff --git a/etherparse/src/transport/icmpv6_header.rs b/etherparse/src/transport/icmpv6_header.rs index 7eaef401..2fdef648 100644 --- a/etherparse/src/transport/icmpv6_header.rs +++ b/etherparse/src/transport/icmpv6_header.rs @@ -3,6 +3,7 @@ use arrayvec::ArrayVec; /// The statically sized data at the start of an ICMPv6 packet (at least the first 8 bytes of an ICMPv6 packet). #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Icmpv6Header { /// Type & type specific values & code. pub icmp_type: Icmpv6Type, diff --git a/etherparse/src/transport/icmpv6_type.rs b/etherparse/src/transport/icmpv6_type.rs index f36393a6..426c2fbd 100644 --- a/etherparse/src/transport/icmpv6_type.rs +++ b/etherparse/src/transport/icmpv6_type.rs @@ -85,6 +85,7 @@ use crate::{ /// # } /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Icmpv6Type { /// In case of an unknown icmp type is received the header elements of /// the first 8 bytes/octets are stored raw in this enum value. diff --git a/etherparse/src/transport/tcp_header.rs b/etherparse/src/transport/tcp_header.rs index a26ce532..6fb27b72 100644 --- a/etherparse/src/transport/tcp_header.rs +++ b/etherparse/src/transport/tcp_header.rs @@ -20,6 +20,7 @@ pub const TCP_MAXIMUM_DATA_OFFSET: u8 = 0xf; /// /// Field descriptions copied from RFC 793 page 15++ #[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TcpHeader { /// The source port number. pub source_port: u16, diff --git a/etherparse/src/transport/tcp_options.rs b/etherparse/src/transport/tcp_options.rs index 8c2720b0..cd3ece73 100644 --- a/etherparse/src/transport/tcp_options.rs +++ b/etherparse/src/transport/tcp_options.rs @@ -126,6 +126,7 @@ use crate::{tcp_option, TcpHeader, TcpOptionElement, TcpOptionWriteError, TcpOpt /// ); /// ``` #[derive(Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TcpOptions { /// Number of bytes in the buffer. pub(crate) len: u8, @@ -134,6 +135,7 @@ pub struct TcpOptions { /// (note that the `len` field defines the actual length). Use /// the options() method if you want to get a slice that has /// the actual length of the options. + #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))] pub(crate) buf: [u8; 40], } diff --git a/etherparse/src/transport/transport_header.rs b/etherparse/src/transport/transport_header.rs index 2fca8c7b..1bf482f0 100644 --- a/etherparse/src/transport/transport_header.rs +++ b/etherparse/src/transport/transport_header.rs @@ -5,6 +5,7 @@ use crate::{ /// The possible headers on the transport layer #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TransportHeader { Udp(UdpHeader), Tcp(TcpHeader), diff --git a/etherparse/src/transport/udp_header.rs b/etherparse/src/transport/udp_header.rs index d4a5279a..d9c97805 100644 --- a/etherparse/src/transport/udp_header.rs +++ b/etherparse/src/transport/udp_header.rs @@ -2,6 +2,7 @@ use crate::{err::ValueTooBigError, *}; /// Udp header according to rfc768. #[derive(Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct UdpHeader { /// Source port of the packet (optional). pub source_port: u16,