etherparse/net/
arp_packet_slice.rs

1use super::{ArpHardwareId, ArpOperation};
2use crate::{
3    err::{Layer, LenError},
4    ArpPacket, EtherType, LenSource,
5};
6
7/// Slice containing an "Address Resolution Protocol" Packet.
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct ArpPacketSlice<'a> {
10    slice: &'a [u8],
11}
12
13impl<'a> ArpPacketSlice<'a> {
14    /// Creates an `ArpPacketSlice` from a slice and verifies that the
15    /// given slice has enough data to contain an complete ARP packet.
16    pub fn from_slice(slice: &'a [u8]) -> Result<ArpPacketSlice<'a>, LenError> {
17        if slice.len() < 8 {
18            return Err(LenError {
19                required_len: 8,
20                len: slice.len(),
21                len_source: LenSource::Slice,
22                layer: Layer::Arp,
23                layer_start_offset: 0,
24            });
25        }
26
27        // validate the rest length based on the hardware & protocol lengths
28        let hw_addr_size = unsafe { *slice.as_ptr().add(4) };
29        let protocol_addr_size = unsafe { *slice.as_ptr().add(5) };
30        let min_len = 8 + (hw_addr_size as usize) * 2 + (protocol_addr_size as usize) * 2;
31
32        if slice.len() < min_len {
33            return Err(LenError {
34                required_len: min_len,
35                len: slice.len(),
36                len_source: LenSource::ArpAddrLengths,
37                layer: Layer::Arp,
38                layer_start_offset: 0,
39            });
40        }
41
42        Ok(Self {
43            slice: unsafe {
44                // SAFETY: Safe as slice was verified above to have a
45                //         length of at least min_len.
46                core::slice::from_raw_parts(slice.as_ptr(), min_len)
47            },
48        })
49    }
50
51    /// Slice containing the ARP packet.
52    #[inline]
53    pub fn slice(&self) -> &'a [u8] {
54        self.slice
55    }
56
57    /// Network link protocol type (e.g. `ArpHardwareId::ETHERNET`).
58    #[inline]
59    pub const fn hw_addr_type(&self) -> ArpHardwareId {
60        ArpHardwareId(u16::from_be_bytes(
61            // SAFE: As the constructor verified the length
62            // of the slice to be at least 8.
63            unsafe { [*self.slice.as_ptr(), *self.slice.as_ptr().add(1)] },
64        ))
65    }
66
67    /// Protocol for which the ARP request is intended (e.g. `EtherType::IPV4`).
68    #[inline]
69    pub const fn proto_addr_type(&self) -> EtherType {
70        EtherType(u16::from_be_bytes(
71            // SAFE: As the constructor verified the length
72            // of the slice to be at least 8.
73            unsafe { [*self.slice.as_ptr().add(2), *self.slice.as_ptr().add(3)] },
74        ))
75    }
76
77    /// Length (in octets) of a hardware address (e.g. 6 for Ethernet).
78    #[inline]
79    pub const fn hw_addr_size(&self) -> u8 {
80        // SAFE: As the constructor verified the length
81        // of the slice to be at least 8.
82        unsafe { *self.slice.as_ptr().add(4) }
83    }
84
85    /// Length (in octets) of network addresses (e.g. 4 for IPv4 or 16 for IPv6).
86    #[inline]
87    pub const fn proto_addr_size(&self) -> u8 {
88        // SAFE: As the constructor verified the length
89        // of the slice to be at least 8.
90        unsafe { *self.slice.as_ptr().add(5) }
91    }
92
93    /// Specifies the operation that the sender is performing
94    #[inline]
95    pub const fn operation(&self) -> ArpOperation {
96        ArpOperation(u16::from_be_bytes(
97            // SAFE: As the constructor verified the length
98            // of the slice to be at least 8.
99            unsafe { [*self.slice.as_ptr().add(6), *self.slice.as_ptr().add(7)] },
100        ))
101    }
102
103    /// Sender hardware address (e.g. MAC address).
104    #[inline]
105    pub const fn sender_hw_addr(&self) -> &[u8] {
106        // SAFETY: Safe as the constructor verifies the
107        //         the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2
108        unsafe {
109            core::slice::from_raw_parts(self.slice.as_ptr().add(8), self.hw_addr_size() as usize)
110        }
111    }
112
113    /// Sender protocol address (e.g. IPv4 address).
114    #[inline]
115    pub const fn sender_protocol_addr(&self) -> &[u8] {
116        // SAFETY: Safe as the constructor verifies the
117        //         the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2
118        unsafe {
119            core::slice::from_raw_parts(
120                self.slice.as_ptr().add(8 + (self.hw_addr_size() as usize)),
121                self.proto_addr_size() as usize,
122            )
123        }
124    }
125
126    /// Target hardware address (e.g. MAC address).
127    #[inline]
128    pub const fn target_hw_addr(&self) -> &[u8] {
129        // SAFETY: Safe as the constructor verifies the
130        //         the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2
131        unsafe {
132            core::slice::from_raw_parts(
133                self.slice
134                    .as_ptr()
135                    .add(8 + (self.hw_addr_size() as usize) + (self.proto_addr_size() as usize)),
136                self.hw_addr_size() as usize,
137            )
138        }
139    }
140
141    /// Buffer containing the target protocol address (e.g. IPv4 address)..
142    #[inline]
143    pub const fn target_protocol_addr(&self) -> &[u8] {
144        // SAFETY: Safe as the constructor verifies the
145        //         the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2
146        unsafe {
147            core::slice::from_raw_parts(
148                self.slice.as_ptr().add(
149                    8 + (self.hw_addr_size() as usize) * 2 + (self.proto_addr_size() as usize),
150                ),
151                self.proto_addr_size() as usize,
152            )
153        }
154    }
155
156    /// Decode fields and return results in an [`ArpPacket`].
157    #[inline]
158    pub fn to_packet(&self) -> ArpPacket {
159        // SAFETY: Safe as all preconditions of new unchecked
160        // are fulfilled by the fact that the on the wire packets already
161        // fulfill them.
162        unsafe {
163            ArpPacket::new_unchecked(
164                self.hw_addr_type(),
165                self.proto_addr_type(),
166                self.operation(),
167                self.sender_hw_addr(),
168                self.sender_protocol_addr(),
169                self.target_hw_addr(),
170                self.target_protocol_addr(),
171            )
172        }
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179    use crate::test_gens::*;
180    use proptest::prelude::*;
181
182    proptest! {
183        #[test]
184        fn from_slice_with_payload(
185            packet in arp_packet_any()
186        ) {
187            // build slice data
188            let data = packet.to_bytes();
189
190            // happy path
191            {
192                let actual = ArpPacketSlice::from_slice(&data).unwrap();
193
194                assert_eq!(actual.hw_addr_type(), packet.hw_addr_type);
195                assert_eq!(actual.proto_addr_type(), packet.proto_addr_type);
196                assert_eq!(actual.hw_addr_size(), packet.hw_addr_size());
197                assert_eq!(actual.proto_addr_size(), packet.protocol_addr_size());
198                assert_eq!(actual.operation(), packet.operation);
199
200                assert_eq!(actual.sender_hw_addr(), packet.sender_hw_addr());
201                assert_eq!(actual.sender_protocol_addr(), packet.sender_protocol_addr());
202                assert_eq!(actual.target_hw_addr(), packet.target_hw_addr());
203                assert_eq!(actual.target_protocol_addr(), packet.target_protocol_addr());
204
205                assert_eq!(&actual.to_packet(), &packet);
206            }
207
208            // length error
209            for len in 0..(8 + (packet.hw_addr_size() as usize)*2 + (packet.protocol_addr_size() as usize)*2) {
210                let err = ArpPacketSlice::from_slice(&data[..len]).unwrap_err();
211                if len < 8 {
212                    assert_eq!(err, LenError{
213                        required_len: 8,
214                        len,
215                        len_source: LenSource::Slice,
216                        layer: Layer::Arp,
217                        layer_start_offset: 0,
218                    });
219                } else {
220                    assert_eq!(err, LenError{
221                        required_len: 8 + (packet.hw_addr_size() as usize)*2 + (packet.protocol_addr_size() as usize)*2,
222                        len,
223                        len_source: LenSource::ArpAddrLengths,
224                        layer: Layer::Arp,
225                        layer_start_offset: 0,
226                    });
227                }
228            }
229        }
230    }
231}