1 use crate::{err::ipv4_exts::ExtsWalkError, *};
2 
3 /// 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(Clone, Debug, Eq, PartialEq, Default)]
11 pub struct Ipv4Extensions {
12     pub auth: Option<IpAuthHeader>,
13 }
14 
15 impl Ipv4Extensions {
16     /// Minimum length required for extension header in bytes/octets.
17     /// Which is zero as no extension headers are required.
18     pub const MIN_LEN: usize = 0;
19 
20     /// Maximum summed up length of all extension headers in bytes/octets.
21     pub const MAX_LEN: usize = IpAuthHeader::MAX_LEN;
22 
23     /// Read all known ipv4 extensions and return an `Ipv4Extensions` with the
24     /// identified slices, the final ip number and a slice pointing to the non parsed data.
from_slice( start_ip_number: IpNumber, slice: &[u8], ) -> Result<(Ipv4Extensions, IpNumber, &[u8]), err::ip_auth::HeaderSliceError>25     pub fn from_slice(
26         start_ip_number: IpNumber,
27         slice: &[u8],
28     ) -> Result<(Ipv4Extensions, IpNumber, &[u8]), err::ip_auth::HeaderSliceError> {
29         Ipv4ExtensionsSlice::from_slice(start_ip_number, slice).map(|v| (v.0.to_header(), v.1, v.2))
30     }
31 
32     /// Collects all known ipv4 extension headers in a slice until an error
33     /// is encountered or a "non IP extension header" is found and
34     /// returns the successfully parsed parts (+ the unparsed slice
35     /// it's [`IpNumber`] and the error if one occurred).
36     ///
37     /// The returned values are
38     ///
39     /// * [`Ipv4Extensions`] containing the successfully parsed IPv6 extension headers
40     /// * [`IpNumber`] of unparsed data
41     /// * Slice with unparsed data
42     /// * Optional with error if there was an error wich stoped the parsing.
43     ///
44     /// # Examples
45     ///
46     /// ```
47     /// use etherparse::{Ipv4Extensions, IpAuthHeader, ip_number::{UDP, AUTHENTICATION_HEADER}};
48     ///
49     /// let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
50     /// let data = auth_header.to_bytes();
51     ///
52     /// let (ipv4_exts, next_ip_num, next_data, err) =
53     ///     Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &data);
54     ///
55     /// // authentication header is separated and no error occurred
56     /// assert!(ipv4_exts.auth.is_some());
57     /// assert_eq!(next_ip_num, UDP);
58     /// assert_eq!(next_data, &[]);
59     /// assert!(err.is_none());
60     /// ```
61     ///
62     /// It is also ok to pass in a "non ip extension":
63     ///
64     /// ```
65     /// use etherparse::{Ipv4Extensions, ip_number::UDP};
66     ///
67     /// let data = [0,1,2,3];
68     /// // passing a non "ip extension header" ip number
69     /// let (ipv4_exts, next_ip_num, next_data, err) =
70     ///     Ipv4Extensions::from_slice_lax(UDP, &data);
71     ///
72     /// // the original data gets returned as UDP is not a
73     /// // an IP extension header
74     /// assert!(ipv4_exts.is_empty());
75     /// assert_eq!(next_ip_num, UDP);
76     /// assert_eq!(next_data, &data);
77     /// // no errors gets triggered as the data is valid
78     /// assert!(err.is_none());
79     /// ```
80     ///
81     /// In case an error occurred the original data gets
82     /// returned together with the error:
83     ///
84     /// ```
85     /// use etherparse::{
86     ///     Ipv4Extensions,
87     ///     IpAuthHeader,
88     ///     ip_number::AUTHENTICATION_HEADER,
89     ///     LenSource,
90     ///     err::{ip_auth::HeaderSliceError::Len, LenError, Layer}
91     /// };
92     ///
93     /// // providing not enough data
94     /// let (ipv4_exts, next_ip_num, next_data, err) =
95     ///     Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &[]);
96     ///
97     /// // original data will be returned with no data parsed
98     /// assert!(ipv4_exts.is_empty());
99     /// assert_eq!(next_ip_num, AUTHENTICATION_HEADER);
100     /// assert_eq!(next_data, &[]);
101     /// // the error that stopped the parsing will also be returned
102     /// assert_eq!(err, Some(Len(LenError{
103     ///     required_len: IpAuthHeader::MIN_LEN,
104     ///     len: 0,
105     ///     len_source: LenSource::Slice,
106     ///     layer: Layer::IpAuthHeader,
107     ///     layer_start_offset: 0,
108     /// })));
109     /// ```
from_slice_lax( start_ip_number: IpNumber, start_slice: &[u8], ) -> ( Ipv4Extensions, IpNumber, &[u8], Option<err::ip_auth::HeaderSliceError>, )110     pub fn from_slice_lax(
111         start_ip_number: IpNumber,
112         start_slice: &[u8],
113     ) -> (
114         Ipv4Extensions,
115         IpNumber,
116         &[u8],
117         Option<err::ip_auth::HeaderSliceError>,
118     ) {
119         let (slice, next_ip_number, next_data, error) =
120             Ipv4ExtensionsSlice::from_slice_lax(start_ip_number, start_slice);
121         (slice.to_header(), next_ip_number, next_data, error)
122     }
123 
124     /// Reads the known ipv4 extension headers from the reader and returns the
125     /// headers together with the internet protocol number identifying the protocol
126     /// that will be next.
127     #[cfg(feature = "std")]
128     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read<T: std::io::Read + Sized>( reader: &mut T, start_ip_number: IpNumber, ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderReadError>129     pub fn read<T: std::io::Read + Sized>(
130         reader: &mut T,
131         start_ip_number: IpNumber,
132     ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderReadError> {
133         use ip_number::*;
134         if AUTH == start_ip_number {
135             let header = IpAuthHeader::read(reader)?;
136             let next_ip_number = header.next_header;
137             Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number))
138         } else {
139             Ok((Default::default(), start_ip_number))
140         }
141     }
142 
143     /// Reads the known ipv4 extension headers from a length limited reader and returns the
144     /// headers together with the internet protocol number identifying the protocol
145     /// that will be next.
146     #[cfg(feature = "std")]
147     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_limited<T: std::io::Read + Sized>( reader: &mut crate::io::LimitedReader<T>, start_ip_number: IpNumber, ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderLimitedReadError>148     pub fn read_limited<T: std::io::Read + Sized>(
149         reader: &mut crate::io::LimitedReader<T>,
150         start_ip_number: IpNumber,
151     ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderLimitedReadError> {
152         use ip_number::*;
153         if AUTH == start_ip_number {
154             let header = IpAuthHeader::read_limited(reader)?;
155             let next_ip_number = header.next_header;
156             Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number))
157         } else {
158             Ok((Default::default(), start_ip_number))
159         }
160     }
161 
162     /// Write the extensions to the writer.
163     #[cfg(feature = "std")]
164     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write<T: std::io::Write + Sized>( &self, writer: &mut T, start_ip_number: IpNumber, ) -> Result<(), err::ipv4_exts::HeaderWriteError>165     pub fn write<T: std::io::Write + Sized>(
166         &self,
167         writer: &mut T,
168         start_ip_number: IpNumber,
169     ) -> Result<(), err::ipv4_exts::HeaderWriteError> {
170         use err::ipv4_exts::{ExtsWalkError::*, HeaderWriteError::*};
171         use ip_number::*;
172         match self.auth {
173             Some(ref header) => {
174                 if AUTH == start_ip_number {
175                     header.write(writer).map_err(Io)
176                 } else {
177                     Err(Content(ExtNotReferenced {
178                         missing_ext: IpNumber::AUTHENTICATION_HEADER,
179                     }))
180                 }
181             }
182             None => Ok(()),
183         }
184     }
185 
186     ///Length of the all present headers in bytes.
header_len(&self) -> usize187     pub fn header_len(&self) -> usize {
188         if let Some(ref header) = self.auth {
189             header.header_len()
190         } else {
191             0
192         }
193     }
194 
195     /// Sets all the next_header fields of the headers based on the adviced default order
196     /// with the given protocol number as last "next header" value. The return value is the protocol
197     /// number of the first existing extension header that should be entered in the ipv4 header as
198     /// protocol_number.
199     ///
200     /// If no extension headers are present the value of the argument is returned.
set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber201     pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber {
202         use ip_number::*;
203 
204         let mut next = last_protocol_number;
205 
206         if let Some(ref mut header) = self.auth {
207             header.next_header = next;
208             next = AUTH;
209         }
210 
211         next
212     }
213 
214     /// Return next header based on the extension headers and
215     /// the first ip protocol number.
216     ///
217     /// In case a header is never referenced a
218     /// [`err::ipv4_exts::ExtsWalkError::ExtNotReferenced`] is returned.
next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError>219     pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> {
220         use ip_number::*;
221         if let Some(ref auth) = self.auth {
222             if first_next_header == AUTH {
223                 Ok(auth.next_header)
224             } else {
225                 Err(ExtsWalkError::ExtNotReferenced {
226                     missing_ext: IpNumber::AUTHENTICATION_HEADER,
227                 })
228             }
229         } else {
230             Ok(first_next_header)
231         }
232     }
233 
234     /// Returns true if no IPv4 extension header is present (all fields `None`).
235     #[inline]
is_empty(&self) -> bool236     pub fn is_empty(&self) -> bool {
237         self.auth.is_none()
238     }
239 }
240 
241 #[cfg(test)]
242 mod test {
243     use super::*;
244     use crate::ip_number::*;
245     use crate::test_gens::*;
246     use alloc::vec::Vec;
247     use proptest::prelude::*;
248     use std::io::Cursor;
249 
250     #[test]
from_slice()251     fn from_slice() {
252         let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
253 
254         let buffer = {
255             let mut buffer = Vec::with_capacity(auth_header.header_len());
256             auth_header.write(&mut buffer).unwrap();
257             buffer.push(1);
258             buffer.push(2);
259             buffer
260         };
261 
262         // no auth header
263         {
264             let (header, next, rest) = Ipv4Extensions::from_slice(TCP, &buffer).unwrap();
265             assert!(header.auth.is_none());
266             assert_eq!(TCP, next);
267             assert_eq!(rest, &buffer);
268         }
269 
270         // with auth header
271         {
272             let (actual, next, rest) = Ipv4Extensions::from_slice(AUTH, &buffer).unwrap();
273             assert_eq!(actual.auth.unwrap(), auth_header);
274             assert_eq!(UDP, next);
275             assert_eq!(rest, &buffer[auth_header.header_len()..]);
276         }
277 
278         // too small
279         {
280             use err::ip_auth::HeaderSliceError::Len;
281             const AUTH_HEADER_LEN: usize = 12;
282             assert_eq!(
283                 Ipv4Extensions::from_slice(AUTH, &buffer[..auth_header.header_len() - 1])
284                     .unwrap_err(),
285                 Len(err::LenError {
286                     required_len: AUTH_HEADER_LEN,
287                     len: auth_header.header_len() - 1,
288                     len_source: LenSource::Slice,
289                     layer: err::Layer::IpAuthHeader,
290                     layer_start_offset: 0,
291                 })
292             );
293         }
294     }
295 
296     proptest! {
297         #[test]
298         fn from_slice_lax(auth in ip_auth_any()) {
299             use crate::ip_number::{UDP, AUTHENTICATION_HEADER};
300             use crate::err::{*, ip_auth::HeaderSliceError::Len};
301 
302             // normal read
303             {
304                 let data = auth.to_bytes();
305 
306                 let (ipv4_exts, next_ip_num, next_data, err) =
307                     Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &data);
308 
309                 // authentication header is separated and no error occurred
310                 assert_eq!(ipv4_exts.auth, Some(auth.clone()));
311                 assert_eq!(next_ip_num, auth.next_header);
312                 assert_eq!(next_data, &[]);
313                 assert!(err.is_none());
314             }
315             // normal read with no extension header
316             {
317                 let data = [0,1,2,3];
318                 // passing a non "ip extension header" ip number
319                 let (ipv4_exts, next_ip_num, next_data, err) =
320                     Ipv4Extensions::from_slice_lax(UDP, &data);
321 
322                 // the original data gets returned as UDP is not a
323                 // an IP extension header
324                 assert!(ipv4_exts.is_empty());
325                 assert_eq!(next_ip_num, UDP);
326                 assert_eq!(next_data, &data);
327                 // no errors gets triggered as the data is valid
328                 assert!(err.is_none());
329             }
330             // len error during parsing
331             {
332                 // providing not enough data
333                 let (ipv4_exts, next_ip_num, next_data, err) =
334                     Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &[]);
335 
336                 // original data will be returned with no data parsed
337                 assert!(ipv4_exts.is_empty());
338                 assert_eq!(next_ip_num, AUTHENTICATION_HEADER);
339                 assert_eq!(next_data, &[]);
340                 // the error that stopped the parsing will also be returned
341                 assert_eq!(err, Some(Len(LenError{
342                     required_len: IpAuthHeader::MIN_LEN,
343                     len: 0,
344                     len_source: LenSource::Slice,
345                     layer: Layer::IpAuthHeader,
346                     layer_start_offset: 0,
347                 })));
348             }
349         }
350     }
351 
352     proptest! {
353         #[test]
354         fn read(auth in ip_auth_any()) {
355             // None
356             {
357                 let mut cursor = Cursor::new(&[]);
358                 let (actual, next) = Ipv4Extensions::read(&mut cursor, UDP).unwrap();
359                 assert_eq!(next, UDP);
360                 assert_eq!(
361                     actual,
362                     Ipv4Extensions{
363                         auth: None,
364                     }
365                 );
366             }
367 
368             // Some sucessfull
369             {
370                 let buffer = {
371                     let mut buffer = Vec::with_capacity(auth.header_len());
372                     auth.write(&mut buffer).unwrap();
373                     buffer.push(1);
374                     buffer
375                 };
376                 let mut cursor = Cursor::new(&buffer);
377                 let (actual, next) = Ipv4Extensions::read(&mut cursor, AUTH).unwrap();
378                 assert_eq!(auth.header_len(), cursor.position() as usize);
379                 assert_eq!(next, auth.next_header);
380                 assert_eq!(
381                     actual,
382                     Ipv4Extensions{
383                         auth: Some(auth.clone()),
384                     }
385                 );
386             }
387 
388             // Some error
389             {
390                 let mut cursor = Cursor::new(&[]);
391                 assert!(Ipv4Extensions::read(&mut cursor, AUTH).is_err());
392             }
393         }
394     }
395 
396     #[test]
write()397     fn write() {
398         // None
399         {
400             let mut buffer = Vec::new();
401             Ipv4Extensions { auth: None }
402                 .write(&mut buffer, UDP)
403                 .unwrap();
404             assert_eq!(0, buffer.len());
405         }
406 
407         // Some
408         let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
409         {
410             let mut buffer = Vec::with_capacity(auth_header.header_len());
411             Ipv4Extensions {
412                 auth: Some(auth_header.clone()),
413             }
414             .write(&mut buffer, AUTH)
415             .unwrap();
416             let (read_header, _) = IpAuthHeader::from_slice(&buffer).unwrap();
417             assert_eq!(auth_header, read_header);
418         }
419 
420         // Some bad start number
421         {
422             use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced;
423 
424             let mut buffer = Vec::new();
425             let err = Ipv4Extensions {
426                 auth: Some(auth_header.clone()),
427             }
428             .write(&mut buffer, UDP)
429             .unwrap_err();
430             assert_eq!(
431                 err.content().unwrap(),
432                 &ExtNotReferenced {
433                     missing_ext: IpNumber::AUTHENTICATION_HEADER,
434                 }
435             );
436         }
437 
438         // Some: Write error
439         {
440             let mut buffer = Vec::with_capacity(auth_header.header_len() - 1);
441             buffer.resize(auth_header.header_len() - 1, 0);
442             let mut cursor = Cursor::new(&mut buffer[..]);
443             let err = Ipv4Extensions {
444                 auth: Some(auth_header.clone()),
445             }
446             .write(&mut cursor, AUTH)
447             .unwrap_err();
448             assert!(err.io().is_some());
449         }
450     }
451 
452     #[test]
header_len()453     fn header_len() {
454         // None
455         assert_eq!(0, Ipv4Extensions { auth: None }.header_len());
456 
457         // Some
458         {
459             let auth = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap();
460             assert_eq!(
461                 auth.header_len(),
462                 Ipv4Extensions { auth: Some(auth) }.header_len()
463             );
464         }
465         // Some with paylaod
466         {
467             let auth = IpAuthHeader::new(UDP, 0, 0, &[1, 2, 3, 4]).unwrap();
468             assert_eq!(
469                 auth.header_len(),
470                 Ipv4Extensions { auth: Some(auth) }.header_len()
471             );
472         }
473     }
474 
475     #[test]
set_next_headers()476     fn set_next_headers() {
477         // None
478         {
479             let mut exts = Ipv4Extensions { auth: None };
480             assert_eq!(UDP, exts.set_next_headers(UDP));
481         }
482 
483         // Some
484         {
485             let mut exts = Ipv4Extensions {
486                 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()),
487             };
488             assert_eq!(TCP, exts.auth.as_ref().unwrap().next_header);
489             // change from TCP to UDP
490             let re = exts.set_next_headers(UDP);
491             assert_eq!(AUTH, re);
492             assert_eq!(UDP, exts.auth.as_ref().unwrap().next_header);
493         }
494     }
495 
496     #[test]
next_header()497     fn next_header() {
498         // None
499         {
500             let exts = Ipv4Extensions { auth: None };
501             assert_eq!(UDP, exts.next_header(UDP).unwrap());
502         }
503         // Some
504         {
505             let exts = Ipv4Extensions {
506                 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()),
507             };
508 
509             // auth referenced
510             assert_eq!(TCP, exts.next_header(AUTH).unwrap());
511 
512             // auth not referenced (error)
513             use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced;
514             assert_eq!(
515                 ExtNotReferenced {
516                     missing_ext: IpNumber::AUTHENTICATION_HEADER
517                 },
518                 exts.next_header(TCP).unwrap_err()
519             );
520         }
521     }
522 
523     #[test]
is_empty()524     fn is_empty() {
525         // empty
526         assert!(Ipv4Extensions { auth: None }.is_empty());
527 
528         // auth
529         assert_eq!(
530             false,
531             Ipv4Extensions {
532                 auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()),
533             }
534             .is_empty()
535         );
536     }
537 
538     proptest! {
539         #[test]
540         fn debug(auth in ip_auth_any()) {
541             use alloc::format;
542 
543             // None
544             assert_eq!(
545                 &format!("Ipv4Extensions {{ auth: {:?} }}", Option::<IpAuthHeader>::None),
546                 &format!(
547                     "{:?}",
548                     Ipv4Extensions {
549                         auth: None,
550                     }
551                 )
552             );
553 
554             // Some
555             assert_eq!(
556                 &format!("Ipv4Extensions {{ auth: {:?} }}", Some(auth.clone())),
557                 &format!(
558                     "{:?}",
559                     Ipv4Extensions {
560                         auth: Some(auth.clone()),
561                     }
562                 )
563             );
564         }
565     }
566 
567     proptest! {
568         #[test]
569         fn clone_eq(auth in ip_auth_any()) {
570             // None
571             {
572                 let header = Ipv4Extensions{
573                     auth: None,
574                 };
575                 assert_eq!(
576                     header.clone(),
577                     Ipv4Extensions{
578                         auth: None,
579                     }
580                 );
581             }
582 
583             // Some
584             {
585                 let header = Ipv4Extensions{
586                     auth: Some(auth.clone()),
587                 };
588                 assert_eq!(
589                     header.clone(),
590                     Ipv4Extensions{
591                         auth: Some(auth.clone()),
592                     }
593                 );
594             }
595         }
596     }
597 }
598