Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
ipv4_exts.rs

1use 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)]
11pub struct Ipv4Extensions {
12    pub auth: Option<IpAuthHeader>,
13}
14
15impl 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.
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    /// ```
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")))]
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")))]
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")))]
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.
187    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.
201    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.
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]
236    pub fn is_empty(&self) -> bool {
237        self.auth.is_none()
238    }
239}
240
241#[cfg(test)]
242mod 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]
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]
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]
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]
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]
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]
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}