• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::{ArpHardwareId, ArpOperation};
2 use 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)]
9 pub struct ArpPacketSlice<'a> {
10     slice: &'a [u8],
11 }
12 
13 impl<'a> ArpPacketSlice<'a> {
14     /// Creates an `ArpPacketSlice` from a slice and verfies that the
15     /// given slice has enough data to contain an complete ARP packet.
from_slice(slice: &'a [u8]) -> Result<ArpPacketSlice<'a>, LenError>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]
slice(&self) -> &'a [u8]53     pub fn slice(&self) -> &'a [u8] {
54         self.slice
55     }
56 
57     /// Network link protocol type (e.g. `ArpHardwareId::ETHERNET`).
58     #[inline]
hw_addr_type(&self) -> ArpHardwareId59     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]
proto_addr_type(&self) -> EtherType69     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]
hw_addr_size(&self) -> u879     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 internetwork addresses (e.g. 4 for IPv4 or 16 for IPv6).
86     #[inline]
proto_addr_size(&self) -> u887     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]
operation(&self) -> ArpOperation95     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]
sender_hw_addr(&self) -> &[u8]105     pub const fn sender_hw_addr(&self) -> &[u8] {
106         // SAFETY: Safe as the constructor verfies 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]
sender_protocol_addr(&self) -> &[u8]115     pub const fn sender_protocol_addr(&self) -> &[u8] {
116         // SAFETY: Safe as the constructor verfies 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]
target_hw_addr(&self) -> &[u8]128     pub const fn target_hw_addr(&self) -> &[u8] {
129         // SAFETY: Safe as the constructor verfies 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]
target_protocol_addr(&self) -> &[u8]143     pub const fn target_protocol_addr(&self) -> &[u8] {
144         // SAFETY: Safe as the constructor verfies 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]
to_packet(&self) -> ArpPacket158     pub fn to_packet(&self) -> ArpPacket {
159         // SAFETY: Safe as all preconditions of new unchecked
160         // are fullfilled by the fact that the on the wire packets already
161         // fullfill 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)]
177 mod 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 }
232