• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     err::{ipv4::SliceError, Layer, LenError},
3     *,
4 };
5 
6 /// Slice containing the IPv4 headers & payload.
7 #[derive(Clone, Debug, Eq, PartialEq)]
8 pub struct Ipv4Slice<'a> {
9     pub(crate) header: Ipv4HeaderSlice<'a>,
10     pub(crate) exts: Ipv4ExtensionsSlice<'a>,
11     pub(crate) payload: IpPayloadSlice<'a>,
12 }
13 
14 impl<'a> Ipv4Slice<'a> {
15     /// Separates and validates IPv4 headers (including extension headers)
16     /// in the given slice and determine the sub-slice containing the payload
17     /// of the IPv4 packet.
18     ///
19     /// Note that his function returns an [`crate::err::LenError`] if the given slice
20     /// contains less data then the `total_len` field in the IPv4 header indicates
21     /// should be present.
22     ///
23     /// If you want to ignore these kind of length errors based on the length
24     /// fields in the IP headers use [`crate::LaxIpv4Slice::from_slice`] instead.
from_slice(slice: &[u8]) -> Result<Ipv4Slice, SliceError>25     pub fn from_slice(slice: &[u8]) -> Result<Ipv4Slice, SliceError> {
26         use crate::ip_number::AUTH;
27 
28         // decode the header
29         let header = Ipv4HeaderSlice::from_slice(slice).map_err(|err| {
30             use crate::err::ipv4::HeaderSliceError::*;
31             match err {
32                 Len(err) => SliceError::Len(err),
33                 Content(err) => SliceError::Header(err),
34             }
35         })?;
36 
37         // validate total_len at least contains the header
38         let header_total_len: usize = header.total_len().into();
39         if header_total_len < header.slice().len() {
40             return Err(SliceError::Len(LenError {
41                 required_len: header.slice().len(),
42                 len: header_total_len,
43                 len_source: LenSource::Ipv4HeaderTotalLen,
44                 layer: Layer::Ipv4Packet,
45                 layer_start_offset: 0,
46             }));
47         }
48 
49         // check slice length based on the total length
50         let header_payload = if slice.len() < header_total_len {
51             return Err(SliceError::Len(LenError {
52                 required_len: header_total_len,
53                 len: slice.len(),
54                 len_source: LenSource::Slice,
55                 layer: Layer::Ipv4Packet,
56                 layer_start_offset: 0,
57             }));
58         } else {
59             unsafe {
60                 core::slice::from_raw_parts(
61                     slice.as_ptr().add(header.slice().len()),
62                     header_total_len - header.slice().len(),
63                 )
64             }
65         };
66 
67         // decode the authentication header if needed
68         let fragmented = header.is_fragmenting_payload();
69         match header.protocol() {
70             AUTH => {
71                 use crate::err::ip_auth::HeaderSliceError as E;
72 
73                 // parse extension headers
74                 let auth = match IpAuthHeaderSlice::from_slice(header_payload) {
75                     Ok(s) => s,
76                     Err(err) => match err {
77                         E::Len(mut l) => {
78                             // change the length source to the ipv4 header
79                             l.len_source = LenSource::Ipv4HeaderTotalLen;
80                             l.layer_start_offset += header.slice().len();
81                             return Err(SliceError::Len(l));
82                         }
83                         E::Content(err) => return Err(SliceError::Exts(err)),
84                     },
85                 };
86 
87                 // remove the extension header from the payload
88                 let payload = unsafe {
89                     core::slice::from_raw_parts(
90                         header_payload.as_ptr().add(auth.slice().len()),
91                         header_payload.len() - auth.slice().len(),
92                     )
93                 };
94                 let ip_number = auth.next_header();
95                 Ok(Ipv4Slice {
96                     header,
97                     exts: Ipv4ExtensionsSlice { auth: Some(auth) },
98                     payload: IpPayloadSlice {
99                         ip_number,
100                         fragmented,
101                         len_source: LenSource::Ipv4HeaderTotalLen,
102                         payload,
103                     },
104                 })
105             }
106             ip_number => Ok(Ipv4Slice {
107                 header,
108                 exts: Ipv4ExtensionsSlice { auth: None },
109                 payload: IpPayloadSlice {
110                     ip_number,
111                     fragmented,
112                     len_source: LenSource::Ipv4HeaderTotalLen,
113                     payload: header_payload,
114                 },
115             }),
116         }
117     }
118 
119     /// Returns a slice containing the IPv4 header.
120     #[inline]
header(&self) -> Ipv4HeaderSlice121     pub fn header(&self) -> Ipv4HeaderSlice {
122         self.header
123     }
124 
125     /// Returns a slice containing the IPv4 extension headers.
126     #[inline]
extensions(&self) -> Ipv4ExtensionsSlice127     pub fn extensions(&self) -> Ipv4ExtensionsSlice {
128         self.exts
129     }
130 
131     /// Returns a slice containing the data after the IPv4 header
132     /// and IPv4 extensions headers.
133     #[inline]
payload(&self) -> &IpPayloadSlice<'a>134     pub fn payload(&self) -> &IpPayloadSlice<'a> {
135         &self.payload
136     }
137 
138     /// Returns the ip number the type of payload of the IPv4 packet.
139     ///
140     /// This function returns the ip number stored in the last
141     /// IPv4 header or extension header.
142     #[inline]
payload_ip_number(&self) -> IpNumber143     pub fn payload_ip_number(&self) -> IpNumber {
144         self.payload.ip_number
145     }
146 
147     /// Returns true if the payload is flagged as being fragmented.
148     #[inline]
is_payload_fragmented(&self) -> bool149     pub fn is_payload_fragmented(&self) -> bool {
150         self.header.is_fragmenting_payload()
151     }
152 }
153 
154 #[cfg(test)]
155 mod test {
156     use super::*;
157     use crate::test_gens::*;
158     use alloc::{format, vec::Vec};
159     use proptest::prelude::*;
160 
161     proptest! {
162         #[test]
163         fn debug_clone_eq(
164             ipv4_base in ipv4_any(),
165             auth in ip_auth_any()
166         ) {
167             let payload: [u8;4] = [1,2,3,4];
168             let mut data = Vec::with_capacity(
169                 ipv4_base.header_len() +
170                 auth.header_len() +
171                 payload.len()
172             );
173             let mut ipv4 = ipv4_base.clone();
174             ipv4.protocol = crate::ip_number::AUTH;
175             ipv4.set_payload_len(auth.header_len() + payload.len()).unwrap();
176             data.extend_from_slice(&ipv4.to_bytes());
177             data.extend_from_slice(&auth.to_bytes());
178             data.extend_from_slice(&payload);
179 
180             // decode packet
181             let slice = Ipv4Slice::from_slice(&data).unwrap();
182 
183             // check debug output
184             prop_assert_eq!(
185                 format!("{:?}", slice),
186                 format!(
187                     "Ipv4Slice {{ header: {:?}, exts: {:?}, payload: {:?} }}",
188                     slice.header(),
189                     slice.extensions(),
190                     slice.payload()
191                 )
192             );
193             prop_assert_eq!(slice.clone(), slice);
194         }
195     }
196 
197     proptest! {
198         #[test]
199         fn from_slice(
200             ipv4_base in ipv4_any(),
201             auth in ip_auth_any()
202         ) {
203             let payload: [u8;6] = [1,2,3,4,5,6];
204 
205             // build packets
206             let data_without_ext = {
207                 let mut data = Vec::with_capacity(
208                     ipv4_base.header_len() +
209                     payload.len() +
210                     4
211                 );
212                 let mut ipv4 = ipv4_base.clone();
213                 ipv4.set_payload_len(payload.len()).unwrap();
214                 ipv4.protocol = crate::ip_number::UDP;
215                 data.extend_from_slice(&ipv4.to_bytes());
216                 data.extend_from_slice(&payload);
217                 data.extend_from_slice(&[0,0,0,0]);
218                 data
219             };
220             let data_with_ext = {
221                 let payload: [u8;6] = [1,2,3,4,5,6];
222                 let mut data = Vec::with_capacity(
223                     ipv4_base.header_len() +
224                     auth.header_len() +
225                     payload.len() +
226                     4
227                 );
228                 let mut ipv4 = ipv4_base.clone();
229                 ipv4.set_payload_len(auth.header_len() + payload.len()).unwrap();
230                 ipv4.protocol = crate::ip_number::AUTH;
231                 data.extend_from_slice(&ipv4.to_bytes());
232                 data.extend_from_slice(&auth.to_bytes());
233                 data.extend_from_slice(&payload);
234                 data.extend_from_slice(&[0,0,0,0]);
235                 data
236             };
237 
238             // parsing without extensions
239             {
240                 let actual = Ipv4Slice::from_slice(&data_without_ext).unwrap();
241                 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv4_base.header_len()]);
242                 prop_assert!(actual.extensions().auth.is_none());
243                 prop_assert_eq!(
244                     &actual.payload,
245                     &IpPayloadSlice{
246                         ip_number: ip_number::UDP.into(),
247                         fragmented: ipv4_base.is_fragmenting_payload(),
248                         len_source: LenSource::Ipv4HeaderTotalLen,
249                         payload: &payload
250                     }
251                 );
252                 prop_assert_eq!(actual.payload_ip_number(), ip_number::UDP.into());
253             }
254 
255             // parsing with extensions
256             {
257                 let actual = Ipv4Slice::from_slice(&data_with_ext).unwrap();
258                 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv4_base.header_len()]);
259                 prop_assert_eq!(
260                     actual.extensions().auth.unwrap(),
261                     IpAuthHeaderSlice::from_slice(&data_with_ext[ipv4_base.header_len()..]).unwrap()
262                 );
263                 prop_assert_eq!(
264                     &actual.payload,
265                     &IpPayloadSlice{
266                         ip_number: auth.next_header.into(),
267                         fragmented: ipv4_base.is_fragmenting_payload(),
268                         len_source: LenSource::Ipv4HeaderTotalLen,
269                         payload: &payload
270                     }
271                 );
272                 prop_assert_eq!(actual.payload_ip_number(), auth.next_header.into());
273             }
274 
275             // header length error
276             for len in 0..Ipv4Header::MIN_LEN {
277                 prop_assert_eq!(
278                     Ipv4Slice::from_slice(&data_without_ext[..len]).unwrap_err(),
279                     SliceError::Len(
280                         LenError{
281                             required_len: Ipv4Header::MIN_LEN,
282                             len,
283                             len_source: LenSource::Slice,
284                             layer: Layer::Ipv4Header,
285                             layer_start_offset: 0,
286                         }
287                     )
288                 );
289             }
290 
291             // header content error
292             {
293                 use crate::err::ipv4::HeaderError;
294                 // inject invalid icv
295                 let mut data = data_without_ext.clone();
296                 data[0] = data[0] & 0xf0; // icv 0
297                 prop_assert_eq!(
298                     Ipv4Slice::from_slice(&data).unwrap_err(),
299                     SliceError::Header(
300                         HeaderError::HeaderLengthSmallerThanHeader { ihl: 0 }
301                     )
302                 );
303             }
304 
305             // payload length error without auth header
306             {
307                 use crate::err::{LenError, Layer};
308 
309                 let required_len = ipv4_base.header_len() + payload.len();
310                 prop_assert_eq!(
311                     Ipv4Slice::from_slice(&data_without_ext[..required_len - 1]).unwrap_err(),
312                     SliceError::Len(LenError{
313                         required_len: required_len,
314                         len: required_len - 1,
315                         len_source: LenSource::Slice,
316                         layer: Layer::Ipv4Packet,
317                         layer_start_offset: 0,
318                     })
319                 );
320             }
321 
322             // payload length error auth header
323             {
324                 use crate::err::{LenError, Layer};
325 
326                 let required_len = ipv4_base.header_len() + auth.header_len() + payload.len();
327                 prop_assert_eq!(
328                     Ipv4Slice::from_slice(&data_with_ext[..required_len - 1]).unwrap_err(),
329                     SliceError::Len(LenError{
330                         required_len: required_len,
331                         len: required_len - 1,
332                         len_source: LenSource::Slice,
333                         layer: Layer::Ipv4Packet,
334                         layer_start_offset: 0,
335                     })
336                 );
337             }
338 
339             // auth length error
340             {
341                 use crate::err::{LenError, Layer};
342 
343                 // inject a total_length that is smaller then the auth header
344                 let mut data = data_with_ext.clone();
345                 let total_len_too_small = ipv4_base.header_len() + auth.header_len() - 1;
346                 {
347                     let tltsm = (total_len_too_small as u16).to_be_bytes();
348                     data[2] = tltsm[0];
349                     data[3] = tltsm[1];
350                 }
351 
352                 prop_assert_eq!(
353                     Ipv4Slice::from_slice(&data).unwrap_err(),
354                     SliceError::Len(
355                         LenError{
356                             required_len: auth.header_len(),
357                             len: auth.header_len() - 1,
358                             len_source: LenSource::Ipv4HeaderTotalLen,
359                             layer: Layer::IpAuthHeader,
360                             layer_start_offset: ipv4_base.header_len(),
361                         }
362                     )
363                 );
364             }
365 
366             // auth content error
367             {
368                 use crate::err::ip_auth::HeaderError;
369 
370                 // inject zero as auth header length
371                 let mut data = data_with_ext.clone();
372                 data[ipv4_base.header_len() + 1] = 0;
373 
374                 prop_assert_eq!(
375                     Ipv4Slice::from_slice(&data).unwrap_err(),
376                     SliceError::Exts(
377                         HeaderError::ZeroPayloadLen
378                     )
379                 );
380             }
381         }
382     }
383 
384     #[test]
is_payload_fragmented()385     fn is_payload_fragmented() {
386         use crate::ip_number::UDP;
387         // non-fragmented
388         {
389             let payload: [u8; 6] = [1, 2, 3, 4, 5, 6];
390             let ipv4 =
391                 Ipv4Header::new(payload.len() as u16, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap();
392             let data = {
393                 let mut data = Vec::with_capacity(ipv4.header_len() + payload.len());
394                 data.extend_from_slice(&ipv4.to_bytes());
395                 data.extend_from_slice(&payload);
396                 data
397             };
398 
399             let slice = Ipv4Slice::from_slice(&data).unwrap();
400             assert!(false == slice.is_payload_fragmented());
401         }
402         // fragmented
403         {
404             let payload: [u8; 6] = [1, 2, 3, 4, 5, 6];
405             let mut ipv4 =
406                 Ipv4Header::new(payload.len() as u16, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap();
407             ipv4.fragment_offset = 123.try_into().unwrap();
408             let data = {
409                 let mut data = Vec::with_capacity(ipv4.header_len() + payload.len());
410                 data.extend_from_slice(&ipv4.to_bytes());
411                 data.extend_from_slice(&payload);
412                 data
413             };
414 
415             let slice = Ipv4Slice::from_slice(&data).unwrap();
416             assert!(slice.is_payload_fragmented());
417         }
418     }
419 }
420