• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 
3 /// Slices of the IPv4 extension headers present after the ip header.
4 ///
5 /// Currently supported:
6 /// * Authentication Header
7 ///
8 /// Currently not supported:
9 /// * Encapsulating Security Payload Header (ESP)
10 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
11 pub struct Ipv4ExtensionsSlice<'a> {
12     pub auth: Option<IpAuthHeaderSlice<'a>>,
13 }
14 
15 impl<'a> Ipv4ExtensionsSlice<'a> {
16     /// Read all known ipv4 extensions and return an `Ipv4ExtensionSlices` with the
17     /// identified slices, the final ip number and a slice pointing to the non parsed data.
from_slice( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> Result<(Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ip_auth::HeaderSliceError>18     pub fn from_slice(
19         start_ip_number: IpNumber,
20         start_slice: &'a [u8],
21     ) -> Result<(Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ip_auth::HeaderSliceError> {
22         use ip_number::*;
23         if AUTH == start_ip_number {
24             let header = IpAuthHeaderSlice::from_slice(start_slice)?;
25             let rest = &start_slice[header.slice().len()..];
26             let next_header = header.next_header();
27             Ok((
28                 Ipv4ExtensionsSlice { auth: Some(header) },
29                 next_header,
30                 rest,
31             ))
32         } else {
33             Ok((Default::default(), start_ip_number, start_slice))
34         }
35     }
36 
37     /// Collects all ipv4 extension headers in a slice until an error
38     /// is encountered or a "non IP extension header" is found and
39     /// returns the successfully parsed parts (+ the unparsed slice
40     /// it's [`IpNumber`] and the error if one occurred).
41     ///
42     /// The returned values are
43     ///
44     /// * [`Ipv4ExtensionsSlice`] containing the successfully parsed IPv6 extension headers
45     /// * [`IpNumber`] of unparsed data
46     /// * Slice with unparsed data
47     /// * Optional with error if there was an error wich stoped the parsing.
48     ///
49     /// # Examples
50     ///
51     /// ```
52     /// use etherparse::{Ipv4ExtensionsSlice, IpAuthHeader, ip_number::{UDP, AUTHENTICATION_HEADER}};
53     ///
54     /// let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
55     /// let data = auth_header.to_bytes();
56     ///
57     /// let (ipv4_exts, next_ip_num, next_data, err) =
58     ///     Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &data);
59     ///
60     /// // authentication header is separated and no error occurred
61     /// assert!(ipv4_exts.auth.is_some());
62     /// assert_eq!(next_ip_num, UDP);
63     /// assert_eq!(next_data, &[]);
64     /// assert!(err.is_none());
65     /// ```
66     ///
67     /// It is also ok to pass in a "non ip extension":
68     ///
69     /// ```
70     /// use etherparse::{Ipv4ExtensionsSlice, ip_number::UDP};
71     ///
72     /// let data = [0,1,2,3];
73     /// // passing a non "ip extension header" ip number
74     /// let (ipv4_exts, next_ip_num, next_data, err) =
75     ///     Ipv4ExtensionsSlice::from_slice_lax(UDP, &data);
76     ///
77     /// // the original data gets returned as UDP is not a
78     /// // an IP extension header
79     /// assert!(ipv4_exts.is_empty());
80     /// assert_eq!(next_ip_num, UDP);
81     /// assert_eq!(next_data, &data);
82     /// // no errors gets triggered as the data is valid
83     /// assert!(err.is_none());
84     /// ```
85     ///
86     /// In case an error occurred the original data gets
87     /// returned together with the error:
88     ///
89     /// ```
90     /// use etherparse::{
91     ///     Ipv4ExtensionsSlice,
92     ///     IpAuthHeader,
93     ///     ip_number::AUTHENTICATION_HEADER,
94     ///     LenSource,
95     ///     err::{ip_auth::HeaderSliceError::Len, LenError, Layer}
96     /// };
97     ///
98     /// // providing not enough data
99     /// let (ipv4_exts, next_ip_num, next_data, err) =
100     ///     Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &[]);
101     ///
102     /// // original data will be returned with no data parsed
103     /// assert!(ipv4_exts.is_empty());
104     /// assert_eq!(next_ip_num, AUTHENTICATION_HEADER);
105     /// assert_eq!(next_data, &[]);
106     /// // the error that stopped the parsing will also be returned
107     /// assert_eq!(err, Some(Len(LenError{
108     ///     required_len: IpAuthHeader::MIN_LEN,
109     ///     len: 0,
110     ///     len_source: LenSource::Slice,
111     ///     layer: Layer::IpAuthHeader,
112     ///     layer_start_offset: 0,
113     /// })));
114     /// ```
from_slice_lax( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> ( Ipv4ExtensionsSlice<'a>, IpNumber, &'a [u8], Option<err::ip_auth::HeaderSliceError>, )115     pub fn from_slice_lax(
116         start_ip_number: IpNumber,
117         start_slice: &'a [u8],
118     ) -> (
119         Ipv4ExtensionsSlice<'a>,
120         IpNumber,
121         &'a [u8],
122         Option<err::ip_auth::HeaderSliceError>,
123     ) {
124         use ip_number::*;
125         if AUTH == start_ip_number {
126             match IpAuthHeaderSlice::from_slice(start_slice) {
127                 Ok(header) => {
128                     let rest = unsafe {
129                         // SAFE as header.slice() has the same start and is a
130                         // subslice of start_slice.
131                         core::slice::from_raw_parts(
132                             start_slice.as_ptr().add(header.slice().len()),
133                             start_slice.len() - header.slice().len(),
134                         )
135                     };
136                     let next_header = header.next_header();
137                     (
138                         Ipv4ExtensionsSlice { auth: Some(header) },
139                         next_header,
140                         rest,
141                         None,
142                     )
143                 }
144                 Err(err) => (
145                     Ipv4ExtensionsSlice { auth: None },
146                     start_ip_number,
147                     start_slice,
148                     Some(err),
149                 ),
150             }
151         } else {
152             (
153                 Ipv4ExtensionsSlice { auth: None },
154                 start_ip_number,
155                 start_slice,
156                 None,
157             )
158         }
159     }
160 
161     /// Convert the slices into actual headers.
to_header(&self) -> Ipv4Extensions162     pub fn to_header(&self) -> Ipv4Extensions {
163         Ipv4Extensions {
164             auth: self.auth.as_ref().map(|v| v.to_header()),
165         }
166     }
167 
168     /// Returns true if no IPv4 extension header is present (all fields `None`).
169     #[inline]
is_empty(&self) -> bool170     pub fn is_empty(&self) -> bool {
171         self.auth.is_none()
172     }
173 }
174 
175 #[cfg(test)]
176 mod test {
177     use super::*;
178     use crate::test_gens::*;
179     use alloc::vec::Vec;
180     use proptest::prelude::*;
181 
182     proptest! {
183         #[test]
184         fn debug(auth in ip_auth_any()) {
185             use alloc::format;
186 
187             // None
188             assert_eq!(
189                 &format!("Ipv4ExtensionsSlice {{ auth: {:?} }}", Option::<IpAuthHeader>::None),
190                 &format!(
191                     "{:?}",
192                     Ipv4ExtensionsSlice {
193                         auth: None,
194                     }
195                 )
196             );
197 
198             // Some
199             let buffer = {
200                 let mut buffer = Vec::with_capacity(auth.header_len());
201                 auth.write(&mut buffer).unwrap();
202                 buffer
203             };
204             let auth_slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
205             assert_eq!(
206                 &format!("Ipv4ExtensionsSlice {{ auth: {:?} }}", Some(auth_slice.clone())),
207                 &format!(
208                     "{:?}",
209                     Ipv4ExtensionsSlice {
210                         auth: Some(auth_slice.clone()),
211                     }
212                 )
213             );
214         }
215     }
216 
217     proptest! {
218         #[test]
219         fn clone_eq(auth in ip_auth_any()) {
220             // None
221             {
222                 let header = Ipv4ExtensionsSlice{
223                     auth: None,
224                 };
225                 assert_eq!(
226                     header.clone(),
227                     Ipv4ExtensionsSlice{
228                         auth: None,
229                     }
230                 );
231             }
232 
233             // Some
234             {
235                 let buffer = {
236                     let mut buffer = Vec::with_capacity(auth.header_len());
237                     auth.write(&mut buffer).unwrap();
238                     buffer
239                 };
240                 let auth_slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
241                 let slice = Ipv4ExtensionsSlice {
242                     auth: Some(auth_slice.clone()),
243                 };
244                 assert_eq!(
245                     slice.clone(),
246                     Ipv4ExtensionsSlice{
247                         auth: Some(auth_slice.clone()),
248                     }
249                 );
250             }
251         }
252     }
253 
254     proptest! {
255         #[test]
256         fn from_slice_lax(auth in ip_auth_any()) {
257             use crate::ip_number::{UDP, AUTHENTICATION_HEADER};
258             use crate::err::{*, ip_auth::HeaderSliceError::Len};
259 
260             // normal read
261             {
262                 let data = auth.to_bytes();
263 
264                 let (ipv4_exts, next_ip_num, next_data, err) =
265                     Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &data);
266 
267                 // authentication header is separated and no error occurred
268                 assert_eq!(ipv4_exts.auth.unwrap().to_header(), auth);
269                 assert_eq!(next_ip_num, auth.next_header);
270                 assert_eq!(next_data, &[]);
271                 assert!(err.is_none());
272             }
273             // normal read with no extension header
274             {
275                 let data = [0,1,2,3];
276                 // passing a non "ip extension header" ip number
277                 let (ipv4_exts, next_ip_num, next_data, err) =
278                     Ipv4ExtensionsSlice::from_slice_lax(UDP, &data);
279 
280                 // the original data gets returned as UDP is not a
281                 // an IP extension header
282                 assert!(ipv4_exts.is_empty());
283                 assert_eq!(next_ip_num, UDP);
284                 assert_eq!(next_data, &data);
285                 // no errors gets triggered as the data is valid
286                 assert!(err.is_none());
287             }
288             // len error during parsing
289             {
290                 // providing not enough data
291                 let (ipv4_exts, next_ip_num, next_data, err) =
292                     Ipv4ExtensionsSlice::from_slice_lax(AUTHENTICATION_HEADER, &[]);
293 
294                 // original data will be returned with no data parsed
295                 assert!(ipv4_exts.is_empty());
296                 assert_eq!(next_ip_num, AUTHENTICATION_HEADER);
297                 assert_eq!(next_data, &[]);
298                 // the error that stopped the parsing will also be returned
299                 assert_eq!(err, Some(Len(LenError{
300                     required_len: IpAuthHeader::MIN_LEN,
301                     len: 0,
302                     len_source: LenSource::Slice,
303                     layer: Layer::IpAuthHeader,
304                     layer_start_offset: 0,
305                 })));
306             }
307         }
308     }
309 
310     proptest! {
311         #[test]
312         fn to_header(auth in ip_auth_any()) {
313             // None
314             assert_eq!(
315                 Ipv4ExtensionsSlice{
316                     auth: None,
317                 }.to_header(),
318                 Ipv4Extensions{
319                     auth: None,
320                 }
321             );
322 
323             // Some
324             {
325                 let buffer = {
326                     let mut buffer = Vec::with_capacity(auth.header_len());
327                     auth.write(&mut buffer).unwrap();
328                     buffer
329                 };
330                 let slice = Ipv4ExtensionsSlice{
331                     auth: Some(
332                         IpAuthHeaderSlice::from_slice(&buffer).unwrap()
333                     ),
334                 };
335                 assert_eq!(
336                     slice.to_header(),
337                     Ipv4Extensions{
338                         auth: Some(auth.clone()),
339                     }
340                 );
341             }
342         }
343     }
344 
345     #[test]
is_empty()346     fn is_empty() {
347         // empty
348         assert!(Ipv4ExtensionsSlice { auth: None }.is_empty());
349 
350         // auth
351         {
352             let buffer = {
353                 let auth = IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap();
354                 let mut buffer = Vec::with_capacity(auth.header_len());
355                 auth.write(&mut buffer).unwrap();
356                 buffer
357             };
358             assert_eq!(
359                 false,
360                 Ipv4ExtensionsSlice {
361                     auth: Some(IpAuthHeaderSlice::from_slice(&buffer).unwrap()),
362                 }
363                 .is_empty()
364             );
365         }
366     }
367 }
368