From e236f3d36f3261bcaadd4e7145e81e7657e11893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20DEROIDE?= Date: Tue, 7 Oct 2025 16:10:01 +0200 Subject: [PATCH 1/2] Use aligned read in getter_be! --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3f21437..19a78b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,11 +23,12 @@ pub mod vxlan; /// # Safety /// /// Caller needs to ensure that the provided field name is in bounds of the struct. +/// Caller needs to ensure that the targeted field is aligned #[cfg(target_endian = "big")] #[macro_export] macro_rules! getter_be { ($self:expr, $field:ident, $ty:ty) => { - ::core::ptr::read_unaligned( + ::core::ptr::read( (($self as *const Self as usize) + ::memoffset::offset_of!(Self, $field)) as *const $ty, ) }; @@ -36,7 +37,7 @@ macro_rules! getter_be { #[macro_export] macro_rules! getter_be { ($self:expr, $field:ident, $ty:ty) => { - ::core::ptr::read_unaligned( + ::core::ptr::read( (($self as *const Self as usize) + ::memoffset::offset_of!(Self, $field)) as *const $ty, ) .swap_bytes() From fe3483eef0ebc9234b594a7133a9fbcb8ee133e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20DEROIDE?= Date: Tue, 7 Oct 2025 16:25:09 +0200 Subject: [PATCH 2/2] Align all headers or L3 and higher protocols --- src/arp.rs | 2 +- src/geneve.rs | 2 +- src/icmp.rs | 24 ++++++++++++------------ src/ip.rs | 4 ++-- src/llc.rs | 2 +- src/mpls.rs | 2 +- src/sctp.rs | 2 +- src/tcp.rs | 2 +- src/udp.rs | 2 +- src/vxlan.rs | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/arp.rs b/src/arp.rs index b142b03..4c6a1cc 100644 --- a/src/arp.rs +++ b/src/arp.rs @@ -7,7 +7,7 @@ use crate::{getter_be, setter_be}; /// The ARP header is typically found after the Ethernet header and is used to /// map a network protocol address (like an IPv4 address) to a hardware /// address (like a MAC address). -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone, Default)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct ArpHdr { diff --git a/src/geneve.rs b/src/geneve.rs index c62b811..4f1286a 100644 --- a/src/geneve.rs +++ b/src/geneve.rs @@ -3,7 +3,7 @@ use crate::{getter_be, setter_be}; /// Represents a Geneve (Generic Network Virtualization Encapsulation) header, according to RFC 8926. /// Geneve is an encapsulation protocol designed for network virtualization. /// -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone, Default)] pub struct GeneveHdr { diff --git a/src/icmp.rs b/src/icmp.rs index 4bc6afa..db75cc9 100644 --- a/src/icmp.rs +++ b/src/icmp.rs @@ -44,7 +44,7 @@ pub enum IcmpError { /// /// The `data` field contains type-specific data such as echo identifiers/sequence numbers, /// redirect gateway addresses, or pointers to errors in received packets. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpHdr { @@ -442,7 +442,7 @@ impl IcmpHdr { /// - `traceroute`: Used for Traceroute messages (Type 30) to hold ID number /// - `photuris`: Used for PHOTURIS security messages (Type 40) to hold SPI and error pointer /// - `reserved`: Generic 4-byte field for types not covered by other variants -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub union IcmpHdrUn { @@ -479,7 +479,7 @@ impl core::fmt::Debug for IcmpHdrUn { /// - 18: Address Mask Reply (deprecated) /// - 37: Domain Name Request (deprecated) /// - 38: Domain Name Reply (deprecated) -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpEcho { @@ -540,7 +540,7 @@ impl IcmpEcho { /// For ICMP Type 3 "Destination Unreachable" Message (RFC 792) with support for PMTUD (RFC 1191) /// Contains 2 unused bytes followed by a Next-Hop MTU field indicating the maximum transmission unit /// of the next-hop network on which fragmentation is required. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpDstUnreachable { @@ -569,7 +569,7 @@ impl IcmpDstUnreachable { /// For ICMP Type 12 "Parameter Problem" Message (RFC 792) /// Contains a pointer to the byte in the original datagram that caused the error /// and 3 bytes of unused padding to make the field a total of 4 bytes. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpParamProblem { @@ -581,7 +581,7 @@ pub struct IcmpParamProblem { /// Contains 2 "Reserved" bytes followed by the Security Parameters Index used /// for a security association between two peers. Also includes a 2-byte pointer /// field indicating where in the message the error was detected. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpHdrPhoturis { @@ -615,7 +615,7 @@ impl IcmpHdrPhoturis { /// Contains a 16-bit ID Number field used by the source to match responses to outgoing requests /// followed by 2 unused bytes to make a total of 4 bytes. The ID Number helps match Reply messages /// (type 31) to their corresponding Requests. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpTraceroute { @@ -720,7 +720,7 @@ impl IcmpTraceroute { /// Ok(0) /// } /// ``` -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpTimestampMsgPart { @@ -828,7 +828,7 @@ impl IcmpTimestampMsgPart { /// Ok(0) /// } /// ``` -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpTracerouteMsgPart { @@ -917,7 +917,7 @@ impl IcmpTracerouteMsgPart { /// /// The `data` field contains type-specific data such as echo identifiers/sequence numbers, /// MTU values, or pointers to errors in received packets. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpV6Hdr { @@ -933,7 +933,7 @@ pub struct IcmpV6Hdr { /// - `packet_too_big_mtu`: Used in Packet Too Big messages (Type 2) to indicate next-hop MTU /// - `param_problem_pointer`: Used in Parameter Problem messages (Type 4) to point to error location /// - `reserved`: Generic 4-byte field for unused/reserved data in other message types -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub union IcmpV6HdrUn { @@ -978,7 +978,7 @@ impl core::fmt::Debug for IcmpV6HdrUn { } } -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct IcmpV6Redirect { diff --git a/src/ip.rs b/src/ip.rs index 8f9573c..15dd70d 100644 --- a/src/ip.rs +++ b/src/ip.rs @@ -10,7 +10,7 @@ pub enum IpHdr { } /// IPv4 header, which is present after the Ethernet header. -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct Ipv4Hdr { @@ -160,7 +160,7 @@ impl Ipv4Hdr { } /// IPv6 header, which is present after the Ethernet header. -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct Ipv6Hdr { diff --git a/src/llc.rs b/src/llc.rs index ba07f8d..a753386 100644 --- a/src/llc.rs +++ b/src/llc.rs @@ -1,7 +1,7 @@ use core::mem; /// Represents Logical Link Control according to ISO/IEC 8802-2 Definition -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct LlcHdr { diff --git a/src/mpls.rs b/src/mpls.rs index 7681b97..f79e344 100644 --- a/src/mpls.rs +++ b/src/mpls.rs @@ -4,7 +4,7 @@ use core::mem; /// https://www.rfc-editor.org/rfc/rfc3032.html. /// This header format applies to all MPLS messages. /// 20 bits for Label - 3 for TC - 1 for S - 8 for TTL -#[repr(C, packed)] +#[repr(C)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct Mpls { diff --git a/src/sctp.rs b/src/sctp.rs index cc4defd..bf2aa6a 100644 --- a/src/sctp.rs +++ b/src/sctp.rs @@ -1,6 +1,6 @@ use core::mem; -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct SctpHdr { diff --git a/src/tcp.rs b/src/tcp.rs index c7073bf..0f14a28 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -5,7 +5,7 @@ use crate::bitfield::BitfieldUnit; pub const TCP_HDR_LEN: usize = mem::size_of::(); /// TCP header, which is present after the IP header. -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct TcpHdr { diff --git a/src/udp.rs b/src/udp.rs index 6d467bd..ee3efd4 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -24,7 +24,7 @@ use crate::{getter_be, setter_be}; /// udp_header.set_len(28); // 8 bytes header + 20 bytes payload /// udp_header.set_checksum(0); // Checksum calculation would be done separately /// ``` -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct UdpHdr { diff --git a/src/vxlan.rs b/src/vxlan.rs index 8caaa71..e55e25c 100644 --- a/src/vxlan.rs +++ b/src/vxlan.rs @@ -6,7 +6,7 @@ use core::mem; /// Uses a 24-bit VXLAN Network Identifier (VNI) for traffic segregation. /// Header length: 8 bytes. /// Reference: RFC 7348. -#[repr(C, packed)] +#[repr(C, align(4))] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct VxlanHdr {