1 use crate::{err::ValueTooBigError, *};
2 
3 /// IPv6 header according to rfc8200.
4 #[derive(Clone, Debug, Eq, PartialEq, Default)]
5 pub struct Ipv6Header {
6     pub traffic_class: u8,
7     /// If non 0 serves as a hint to router and switches with multiple outbound paths that these packets should stay on the same path, so that they will not be reordered.
8     pub flow_label: Ipv6FlowLabel,
9     ///The length of the payload and extension headers in bytes (0 in case of jumbo payloads).
10     pub payload_length: u16,
11     /// IP protocol number specifying the next header or transport layer protocol.
12     ///
13     /// See [IpNumber] or [ip_number] for a definitions of ids.
14     pub next_header: IpNumber,
15     /// The number of hops the packet can take before it is discarded.
16     pub hop_limit: u8,
17     /// IPv6 source address
18     pub source: [u8; 16],
19     /// IPv6 destination address
20     pub destination: [u8; 16],
21 }
22 
23 impl Ipv6Header {
24     /// Serialized size of an IPv6 header in bytes/octets.
25     pub const LEN: usize = 40;
26 
27     #[deprecated(since = "0.14.0", note = "Use `Ipv6Header::LEN` instead")]
28     pub const SERIALIZED_SIZE: usize = Ipv6Header::LEN;
29 
30     /// Renamed to `Ipv6Header::from_slice`
31     #[deprecated(since = "0.10.1", note = "Renamed to `Ipv6Header::from_slice`")]
32     #[inline]
read_from_slice( slice: &[u8], ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError>33     pub fn read_from_slice(
34         slice: &[u8],
35     ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> {
36         Ipv6Header::from_slice(slice)
37     }
38 
39     /// Read an Ipv6Header from a slice and return the header & unused parts of the slice.
40     ///
41     /// Note that this function DOES NOT seperate the payload based on the length
42     /// payload_length present in the IPv6 header. It just returns the left over slice
43     /// after the header.
44     ///
45     /// If you want to have correctly seperated payload including the IP extension
46     /// headers use
47     ///
48     /// * [`crate::IpHeaders::from_ipv6_slice`] (decodes all the fields of the IP headers)
49     /// * [`crate::Ipv6Slice::from_slice`] (just identifies the ranges in the slice where
50     ///   the headers and payload are present)
51     ///
52     /// or
53     ///
54     /// * [`crate::IpHeaders::from_ipv6_slice_lax`]
55     /// * [`crate::Ipv6Slice::from_slice_lax`]
56     ///
57     /// for a laxer version which falls back to slice length when the `payload_length`
58     /// contains an inconsistent value.
59     #[inline]
from_slice(slice: &[u8]) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError>60     pub fn from_slice(slice: &[u8]) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> {
61         Ok((
62             Ipv6HeaderSlice::from_slice(slice)?.to_header(),
63             &slice[Ipv6Header::LEN..],
64         ))
65     }
66 
67     ///Reads an IPv6 header from the current position.
68     #[cfg(feature = "std")]
69     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<Ipv6Header, err::ipv6::HeaderReadError>70     pub fn read<T: std::io::Read + std::io::Seek + Sized>(
71         reader: &mut T,
72     ) -> Result<Ipv6Header, err::ipv6::HeaderReadError> {
73         use err::ipv6::{HeaderError::*, HeaderReadError::*};
74 
75         let mut value: [u8; 1] = [0; 1];
76         reader.read_exact(&mut value).map_err(Io)?;
77         let version_number = value[0] >> 4;
78         if 6 != version_number {
79             return Err(Content(UnexpectedVersion { version_number }));
80         }
81         Ipv6Header::read_without_version(reader, value[0] & 0xf).map_err(Io)
82     }
83 
84     ///Reads an IPv6 header assuming the version & flow_label field have already been read.
85     #[cfg(feature = "std")]
86     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_without_version<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, version_rest: u8, ) -> Result<Ipv6Header, std::io::Error>87     pub fn read_without_version<T: std::io::Read + std::io::Seek + Sized>(
88         reader: &mut T,
89         version_rest: u8,
90     ) -> Result<Ipv6Header, std::io::Error> {
91         let mut buffer: [u8; 8 + 32 - 1] = [0; 8 + 32 - 1];
92         reader.read_exact(&mut buffer[..])?;
93 
94         Ok(Ipv6Header {
95             traffic_class: (version_rest << 4) | (buffer[0] >> 4),
96             flow_label: unsafe {
97                 // SAFETY: Safe as the bitmask & 0 contant guarantee that the value
98                 // does not exceed 20 bytes.
99                 Ipv6FlowLabel::new_unchecked(u32::from_be_bytes([
100                     0,
101                     buffer[0] & 0b0000_1111,
102                     buffer[1],
103                     buffer[2],
104                 ]))
105             },
106             payload_length: u16::from_be_bytes([buffer[3], buffer[4]]),
107             next_header: IpNumber(buffer[5]),
108             hop_limit: buffer[6],
109             #[rustfmt::skip]
110             source: [
111                 buffer[7],   buffer[8],  buffer[9], buffer[10],
112                 buffer[11], buffer[12], buffer[13], buffer[14],
113                 buffer[15], buffer[16], buffer[17], buffer[18],
114                 buffer[19], buffer[20], buffer[21], buffer[22],
115             ],
116             #[rustfmt::skip]
117             destination: [
118                 buffer[23], buffer[24], buffer[25], buffer[26],
119                 buffer[27], buffer[28], buffer[29], buffer[30],
120                 buffer[31], buffer[32], buffer[33], buffer[34],
121                 buffer[35], buffer[36], buffer[37], buffer[38],
122             ],
123         })
124     }
125 
126     ///Takes a slice and skips an ipv6 header extensions and returns the next_header ip number & the slice past the header.
skip_header_extension_in_slice( slice: &[u8], next_header: IpNumber, ) -> Result<(IpNumber, &[u8]), err::LenError>127     pub fn skip_header_extension_in_slice(
128         slice: &[u8],
129         next_header: IpNumber,
130     ) -> Result<(IpNumber, &[u8]), err::LenError> {
131         use crate::ip_number::*;
132 
133         // verify that a ipv6 extension is present (before
134         // validating the slice length)
135         match next_header {
136             IPV6_FRAG | AUTH | IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY
137             | HIP | SHIM6 => {}
138             _ => {
139                 return Ok((next_header, slice));
140             }
141         }
142 
143         if slice.len() >= 2 {
144             //determine the length
145             let len = match next_header {
146                 IPV6_FRAG => 8,
147                 AUTH => (usize::from(slice[1]) + 2) * 4,
148                 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => {
149                     (usize::from(slice[1]) + 1) * 8
150                 }
151                 // not a ipv6 header extension that can be skipped
152                 _ => unreachable!(),
153             };
154 
155             if slice.len() < len {
156                 Err(err::LenError {
157                     required_len: len,
158                     len: slice.len(),
159                     len_source: LenSource::Slice,
160                     layer: err::Layer::Ipv6ExtHeader,
161                     layer_start_offset: 0,
162                 })
163             } else {
164                 Ok((IpNumber(slice[0]), &slice[len..]))
165             }
166         } else {
167             Err(err::LenError {
168                 required_len: 2,
169                 len: slice.len(),
170                 len_source: LenSource::Slice,
171                 layer: err::Layer::Ipv6ExtHeader,
172                 layer_start_offset: 0,
173             })
174         }
175     }
176 
177     /// Returns true if the given ip protocol number is a skippable header extension.
178     ///
179     /// A skippable header extension is an extension header for which it is known how
180     /// to determine the protocol number of the following header as well as how many
181     /// octets have to be skipped to reach the start of the following header.
is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool182     pub fn is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool {
183         use crate::ip_number::*;
184         //Note: EncapsulatingSecurityPayload & ExperimentalAndTesting0 can not be skipped
185         matches!(
186             ip_protocol_number,
187             IPV6_HOP_BY_HOP
188                 | IPV6_ROUTE
189                 | IPV6_FRAG
190                 | AUTH
191                 | IPV6_DEST_OPTIONS
192                 | MOBILITY
193                 | HIP
194                 | SHIM6
195         )
196     }
197 
198     ///Takes a slice & ip protocol number (identifying the first header type) and returns next_header id & the slice past after all ipv6 header extensions.
skip_all_header_extensions_in_slice( slice: &[u8], next_header: IpNumber, ) -> Result<(IpNumber, &[u8]), err::LenError>199     pub fn skip_all_header_extensions_in_slice(
200         slice: &[u8],
201         next_header: IpNumber,
202     ) -> Result<(IpNumber, &[u8]), err::LenError> {
203         let mut next_header = next_header;
204         let mut rest = slice;
205         let mut offset = 0;
206 
207         loop {
208             let (n_id, n_rest) = Ipv6Header::skip_header_extension_in_slice(rest, next_header)
209                 .map_err(|err| err.add_offset(offset))?;
210             offset = slice.len() - n_rest.len();
211 
212             if n_rest.len() == rest.len() {
213                 return Ok((next_header, rest));
214             } else {
215                 next_header = n_id;
216                 rest = n_rest;
217             }
218         }
219     }
220 
221     ///Skips the ipv6 header extension and returns the next ip protocol number
222     #[cfg(feature = "std")]
223     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
skip_header_extension<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, next_header: IpNumber, ) -> Result<IpNumber, std::io::Error>224     pub fn skip_header_extension<T: std::io::Read + std::io::Seek + Sized>(
225         reader: &mut T,
226         next_header: IpNumber,
227     ) -> Result<IpNumber, std::io::Error> {
228         use crate::ip_number::*;
229 
230         let (next_header, rest_length) = match next_header {
231             IPV6_FRAG => {
232                 let mut buf = [0; 1];
233                 reader.read_exact(&mut buf)?;
234                 (IpNumber(buf[0]), 7)
235             }
236             AUTH => {
237                 let mut buf = [0; 2];
238                 reader.read_exact(&mut buf)?;
239                 (IpNumber(buf[0]), i64::from(buf[1]) * 4 + 6)
240             }
241             IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => {
242                 let mut buf = [0; 2];
243                 reader.read_exact(&mut buf)?;
244                 (IpNumber(buf[0]), i64::from(buf[1]) * 8 + 6)
245             }
246             // not a ipv6 header extension that can be skipped
247             _ => return Ok(next_header),
248         };
249 
250         //Sadly seek does not return an error if the seek could not be fulfilled.
251         //Some implementations do not even truncate the returned position to the
252         //last valid one. std::io::Cursor for example just moves the position
253         //over the border of the given slice (e.g. returns position 15 even when
254         //the given slice contains only 1 element).
255         //The only option, to detect that we are in an invalid state, is to move the
256         //seek offset to one byte before the end and then execute a normal read to
257         //trigger an error.
258         reader.seek(std::io::SeekFrom::Current(rest_length - 1))?;
259         {
260             let mut buf = [0; 1];
261             reader.read_exact(&mut buf)?;
262         }
263         Ok(next_header)
264     }
265 
266     ///Skips all ipv6 header extensions and returns the next ip protocol number
267     #[cfg(feature = "std")]
268     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
skip_all_header_extensions<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, next_header: IpNumber, ) -> Result<IpNumber, std::io::Error>269     pub fn skip_all_header_extensions<T: std::io::Read + std::io::Seek + Sized>(
270         reader: &mut T,
271         next_header: IpNumber,
272     ) -> Result<IpNumber, std::io::Error> {
273         let mut next_header = next_header;
274 
275         loop {
276             if Ipv6Header::is_skippable_header_extension(next_header) {
277                 next_header = Ipv6Header::skip_header_extension(reader, next_header)?;
278             } else {
279                 return Ok(next_header);
280             }
281         }
282     }
283 
284     ///Writes a given IPv6 header to the current position.
285     #[cfg(feature = "std")]
286     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error>287     pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
288         writer.write_all(&self.to_bytes())
289     }
290 
291     /// Return the ipv6 source address as an std::net::Ipv6Addr
292     #[cfg(feature = "std")]
293     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
294     #[inline]
source_addr(&self) -> std::net::Ipv6Addr295     pub fn source_addr(&self) -> std::net::Ipv6Addr {
296         std::net::Ipv6Addr::from(self.source)
297     }
298 
299     /// Return the ipv6 destination address as an std::net::Ipv6Addr
300     #[cfg(feature = "std")]
301     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
302     #[inline]
destination_addr(&self) -> std::net::Ipv6Addr303     pub fn destination_addr(&self) -> std::net::Ipv6Addr {
304         std::net::Ipv6Addr::from(self.destination)
305     }
306 
307     /// Length of the serialized header in bytes.
308     ///
309     /// The function always returns the constant Ipv6Header::LEN
310     /// and exists to keep the methods consistent with other headers.
311     #[inline]
header_len(&self) -> usize312     pub fn header_len(&self) -> usize {
313         Ipv6Header::LEN
314     }
315 
316     /// Sets the field total_length based on the size of the payload and the options. Returns an error if the payload is too big to fit.
set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>>317     pub fn set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>> {
318         use crate::err::ValueType;
319         // check that the total length fits into the field
320         const MAX_PAYLOAD_LENGTH: usize = u16::MAX as usize;
321         if MAX_PAYLOAD_LENGTH < size {
322             return Err(ValueTooBigError {
323                 actual: size,
324                 max_allowed: MAX_PAYLOAD_LENGTH,
325                 value_type: ValueType::Ipv6PayloadLength,
326             });
327         }
328 
329         self.payload_length = size as u16;
330         Ok(())
331     }
332 
333     /// Returns the serialized form of the header as a statically
334     /// sized byte array.
335     #[rustfmt::skip]
to_bytes(&self) -> [u8;Ipv6Header::LEN]336     pub fn to_bytes(&self) -> [u8;Ipv6Header::LEN] {
337         // serialize header
338         let flow_label_be = self.flow_label.value().to_be_bytes();
339         let payload_len_be = self.payload_length.to_be_bytes();
340 
341         [
342             (6 << 4) | (self.traffic_class >> 4),
343             (self.traffic_class << 4) | flow_label_be[1],
344             flow_label_be[2],
345             flow_label_be[3],
346             payload_len_be[0],
347             payload_len_be[1],
348             self.next_header.0,
349             self.hop_limit,
350             self.source[0], self.source[1], self.source[2], self.source[3],
351             self.source[4], self.source[5], self.source[6], self.source[7],
352             self.source[8], self.source[9], self.source[10], self.source[11],
353             self.source[12], self.source[13], self.source[14], self.source[15],
354             self.destination[0], self.destination[1], self.destination[2], self.destination[3],
355             self.destination[4], self.destination[5], self.destination[6], self.destination[7],
356             self.destination[8], self.destination[9], self.destination[10], self.destination[11],
357             self.destination[12], self.destination[13], self.destination[14], self.destination[15],
358         ]
359     }
360 }
361 
362 #[cfg(test)]
363 mod test {
364     use crate::{
365         err::ipv6::HeaderError::*, err::ipv6::HeaderSliceError::*, ip_number::*, test_gens::*, *,
366     };
367     use alloc::format;
368     use arrayvec::ArrayVec;
369     use proptest::*;
370     use std::io::Cursor;
371 
372     #[test]
default()373     fn default() {
374         let header: Ipv6Header = Default::default();
375         assert_eq!(0, header.traffic_class);
376         assert_eq!(0, header.flow_label.value());
377         assert_eq!(0, header.payload_length);
378         assert_eq!(255, header.next_header.0);
379         assert_eq!(0, header.hop_limit);
380         assert_eq!([0u8; 16], header.source);
381         assert_eq!([0u8; 16], header.destination);
382     }
383 
384     #[test]
debug()385     fn debug() {
386         let header: Ipv6Header = Default::default();
387         assert_eq!(
388             format!("{:?}", header),
389             format!(
390                 "Ipv6Header {{ traffic_class: {}, flow_label: {:?}, payload_length: {}, next_header: {:?}, hop_limit: {}, source: {:?}, destination: {:?} }}",
391                 header.traffic_class,
392                 header.flow_label,
393                 header.payload_length,
394                 header.next_header,
395                 header.hop_limit,
396                 header.source,
397                 header.destination
398             )
399         );
400     }
401 
402     proptest! {
403         #[test]
404         fn clone_eq(header in ipv6_any()) {
405             assert_eq!(header.clone(), header);
406         }
407     }
408 
409     proptest! {
410         #[test]
411         #[allow(deprecated)]
412         fn read_from_slice(
413             header in ipv6_any(),
414             bad_version in 0..=0b1111u8
415         ) {
416             // ok read
417             {
418                 let bytes = header.to_bytes();
419                 let (actual, rest) = Ipv6Header::read_from_slice(&bytes).unwrap();
420                 assert_eq!(header, actual);
421                 assert_eq!(rest, &[]);
422             }
423 
424             // version error
425             if bad_version != 6 {
426                 let mut bytes = header.to_bytes();
427                 // inject a bad version number
428                 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
429 
430                 assert_eq!(
431                     Ipv6Header::read_from_slice(&bytes).unwrap_err(),
432                     Content(UnexpectedVersion{ version_number: bad_version })
433                 );
434             }
435 
436             // length error
437             {
438                 let bytes = header.to_bytes();
439                 for len in 0..bytes.len() {
440                     assert_eq!(
441                         Ipv6Header::read_from_slice(&bytes[..len])
442                             .unwrap_err(),
443                         Len(err::LenError{
444                             required_len: Ipv6Header::LEN,
445                             len: len,
446                             len_source: LenSource::Slice,
447                             layer: err::Layer::Ipv6Header,
448                             layer_start_offset: 0,
449                         })
450                     );
451                 }
452             }
453         }
454     }
455 
456     proptest! {
457         #[test]
458         fn from_slice(
459             header in ipv6_any(),
460             bad_version in 0..=0b1111u8
461         ) {
462             // ok read
463             {
464                 let bytes = header.to_bytes();
465                 let (actual, rest) = Ipv6Header::from_slice(&bytes).unwrap();
466                 assert_eq!(header, actual);
467                 assert_eq!(rest, &[]);
468             }
469 
470             // version error
471             if bad_version != 6 {
472                 let mut bytes = header.to_bytes();
473                 // inject a bad version number
474                 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
475 
476                 assert_eq!(
477                     Ipv6Header::from_slice(&bytes).unwrap_err(),
478                     Content(UnexpectedVersion{ version_number: bad_version })
479                 );
480             }
481 
482             // length error
483             {
484                 let bytes = header.to_bytes();
485                 for len in 0..bytes.len() {
486                     assert_eq!(
487                         Ipv6Header::from_slice(&bytes[..len])
488                             .unwrap_err(),
489                         Len(err::LenError{
490                             required_len: Ipv6Header::LEN,
491                             len: len,
492                             len_source: LenSource::Slice,
493                             layer: err::Layer::Ipv6Header,
494                             layer_start_offset: 0,
495                         })
496                     );
497                 }
498             }
499         }
500     }
501 
502     proptest! {
503         #[test]
504         fn read(
505             header in ipv6_any(),
506             bad_version in 0..=0b1111u8
507         ) {
508             use err::ipv6::HeaderError::*;
509 
510             // ok read
511             {
512                 let bytes = header.to_bytes();
513                 let mut cursor = Cursor::new(&bytes[..]);
514                 let actual = Ipv6Header::read(&mut cursor).unwrap();
515                 assert_eq!(header, actual);
516                 assert_eq!(cursor.position(), bytes.len() as u64);
517             }
518 
519             // version error
520             if bad_version != 6 {
521                 let mut bytes = header.to_bytes();
522                 // inject a bad version number
523                 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
524 
525                 let mut cursor = Cursor::new(&bytes[..]);
526                 assert_eq!(
527                     Ipv6Header::read(&mut cursor)
528                         .unwrap_err()
529                         .content_error()
530                         .unwrap(),
531                     UnexpectedVersion {
532                         version_number: bad_version,
533                     }
534                 );
535             }
536 
537             // io error
538             {
539                 let bytes = header.to_bytes();
540                 for len in 0..bytes.len() {
541                     let mut cursor = Cursor::new(&bytes[..len]);
542                     assert!(Ipv6Header::read(&mut cursor).is_err());
543                 }
544             }
545         }
546     }
547 
548     proptest! {
549         #[test]
550         fn read_without_version(header in ipv6_any()) {
551             // ok read
552             {
553                 let bytes = header.to_bytes();
554                 let mut cursor = Cursor::new(&bytes[1..]);
555                 let actual = Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).unwrap();
556                 assert_eq!(header, actual);
557                 assert_eq!(cursor.position(), bytes.len() as u64 - 1);
558             }
559 
560             // io error
561             {
562                 let bytes = header.to_bytes();
563                 for len in 1..bytes.len() {
564                     let mut cursor = Cursor::new(&bytes[1..len]);
565                     assert!(Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).is_err());
566                 }
567             }
568         }
569     }
570 
571     proptest! {
572         #[test]
573         fn skip_header_extension_in_slice(
574             generic in ipv6_raw_ext_any(),
575             frag in ipv6_fragment_any(),
576             auth in ip_auth_any()
577         ) {
578             const GENERICS: [IpNumber;7] = [
579                 IPV6_HOP_BY_HOP,
580                 IPV6_DEST_OPTIONS,
581                 IPV6_ROUTE,
582                 IPV6_DEST_OPTIONS,
583                 MOBILITY,
584                 HIP,
585                 SHIM6,
586             ];
587 
588             // generic headers
589             for g in GENERICS {
590                 let bytes = generic.to_bytes();
591                 // ok case
592                 {
593                     let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, g).unwrap();
594                     assert_eq!(next, generic.next_header);
595                     assert_eq!(rest, &[]);
596                 }
597                 // length error
598                 for len in 0..bytes.len() {
599                     assert_eq!(
600                         Ipv6Header::skip_header_extension_in_slice(&bytes[..len], g).unwrap_err(),
601                         err::LenError {
602                             required_len: if len < 2 {
603                                 2
604                             } else {
605                                 bytes.len()
606                             },
607                             len: len,
608                             len_source: LenSource::Slice,
609                             layer: err::Layer::Ipv6ExtHeader,
610                             layer_start_offset: 0,
611                         }
612                     );
613                 }
614             }
615             // frag header
616             {
617                 let bytes = frag.to_bytes();
618                 // ok case
619                 {
620                     let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, IPV6_FRAG).unwrap();
621                     assert_eq!(next, frag.next_header);
622                     assert_eq!(rest, &[]);
623                 }
624                 // length error
625                 for len in 0..bytes.len() {
626                     assert_eq!(
627                         Ipv6Header::skip_header_extension_in_slice(&bytes[..len], IPV6_FRAG).unwrap_err(),
628                         err::LenError {
629                             required_len: if len < 2 {
630                                 2
631                             } else {
632                                 bytes.len()
633                             },
634                             len: len,
635                             len_source: LenSource::Slice,
636                             layer: err::Layer::Ipv6ExtHeader,
637                             layer_start_offset: 0,
638                         }
639                     );
640                 }
641             }
642 
643             // auth header
644             {
645                 let bytes = auth.to_bytes();
646                 // ok case
647                 {
648                     let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, AUTH).unwrap();
649                     assert_eq!(next, auth.next_header);
650                     assert_eq!(rest, &[]);
651                 }
652                 // length error
653                 for len in 0..bytes.len() {
654                     assert_eq!(
655                         Ipv6Header::skip_header_extension_in_slice(&bytes[..len], AUTH).unwrap_err(),
656                         err::LenError {
657                             required_len: if len < 2 {
658                                 2
659                             } else {
660                                 bytes.len()
661                             },
662                             len: len,
663                             len_source: LenSource::Slice,
664                             layer: err::Layer::Ipv6ExtHeader,
665                             layer_start_offset: 0,
666                         }
667                     );
668                 }
669             }
670         }
671     }
672 
673     #[test]
is_skippable_header_extension()674     fn is_skippable_header_extension() {
675         for i in 0..0xffu8 {
676             let expected = match IpNumber(i) {
677                 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_FRAG | AUTH | IPV6_DEST_OPTIONS | MOBILITY
678                 | HIP | SHIM6 => true,
679                 _ => false,
680             };
681             assert_eq!(
682                 expected,
683                 Ipv6Header::is_skippable_header_extension(IpNumber(i))
684             );
685         }
686     }
687 
688     proptest! {
689         #[test]
690         fn skip_all_header_extensions_in_slice(
691             hop_by_hop in ipv6_raw_ext_any(),
692             dst_opt1 in ipv6_raw_ext_any(),
693             route in ipv6_raw_ext_any(),
694             frag in ipv6_fragment_any(),
695             auth in ip_auth_any(),
696             dst_opt2 in ipv6_raw_ext_any(),
697             mobility in ipv6_raw_ext_any(),
698             hip in ipv6_raw_ext_any(),
699             shim6 in ipv6_raw_ext_any()
700         ) {
701             // no extension header
702             {
703                 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&[], UDP).unwrap();
704                 assert_eq!(UDP, next);
705                 assert_eq!(rest, &[]);
706             }
707 
708             // setup a buffer with all extension headers present
709             let buffer = {
710                 let mut buffer = ArrayVec::<u8, {
711                     Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
712                 }>::new();
713 
714                 // based on RFC 8200 4.1. Extension Header Order
715                 // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
716                 //
717                 // IPV6_HOP_BY_HOP,
718                 // IPV6_DEST_OPTIONS,
719                 // IPV6_ROUTE,
720                 // IPV6_FRAG,
721                 // AUTH,
722                 // IPV6_DEST_OPTIONS,
723                 // MOBILITY,
724                 // HIP,
725                 // SHIM6,
726 
727                 let mut hop_by_hop = hop_by_hop.clone();
728                 hop_by_hop.next_header = IPV6_DEST_OPTIONS;
729                 buffer.extend(hop_by_hop.to_bytes());
730 
731                 let mut dst_opt1 = dst_opt1.clone();
732                 dst_opt1.next_header = IPV6_ROUTE;
733                 buffer.extend(dst_opt1.to_bytes());
734 
735                 let mut route = route.clone();
736                 route.next_header = IPV6_FRAG;
737                 buffer.extend(route.to_bytes());
738 
739                 let mut frag = frag.clone();
740                 frag.next_header = AUTH;
741                 buffer.extend(frag.to_bytes());
742 
743                 let mut auth = auth.clone();
744                 auth.next_header = IPV6_DEST_OPTIONS;
745                 buffer.extend(auth.to_bytes());
746 
747                 let mut dst_opt2 = dst_opt2.clone();
748                 dst_opt2.next_header = MOBILITY;
749                 buffer.extend(dst_opt2.to_bytes());
750 
751                 let mut mobility = mobility.clone();
752                 mobility.next_header = HIP;
753                 buffer.extend(mobility.to_bytes());
754 
755                 let mut hip = hip.clone();
756                 hip.next_header = SHIM6;
757                 buffer.extend(hip.to_bytes());
758 
759                 let mut shim6 = shim6.clone();
760                 shim6.next_header = TCP;
761                 buffer.extend(shim6.to_bytes());
762 
763                 buffer
764             };
765 
766             // ok skip case with all extension headers
767             {
768                 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&buffer, IPV6_HOP_BY_HOP).unwrap();
769                 assert_eq!(next, TCP);
770                 assert_eq!(rest, &[]);
771             }
772 
773             // length error
774             {
775                 let len_ranges: [usize;9] = [
776                     hop_by_hop.header_len(),
777                     dst_opt1.header_len(),
778                     route.header_len(),
779                     frag.header_len(),
780                     auth.header_len(),
781                     dst_opt2.header_len(),
782                     mobility.header_len(),
783                     hip.header_len(),
784                     shim6.header_len()
785                 ];
786                 let get_expected = |len: usize| -> usize{
787                     let mut curr = 0;
788                     for next in &len_ranges {
789                         if len < curr {
790                             break;
791                         }
792                         if len < curr + 2 {
793                             curr += 2;
794                             break;
795                         }
796                         curr += next;
797                     }
798                     curr
799                 };
800 
801                 let get_offset = |len: usize| -> usize{
802                     let mut curr = 0;
803                     for next in &len_ranges {
804                         if len < curr + next {
805                             break;
806                         }
807                         curr += next;
808                     }
809                     curr
810                 };
811 
812                 for len in 0..buffer.len() {
813                     assert_eq!(
814                         Ipv6Header::skip_all_header_extensions_in_slice(&buffer[..len], IPV6_HOP_BY_HOP)
815                             .unwrap_err(),
816                         err::LenError {
817                             required_len: get_expected(len) - get_offset(len),
818                             len: len - get_offset(len),
819                             len_source: LenSource::Slice,
820                             layer: err::Layer::Ipv6ExtHeader,
821                             layer_start_offset: get_offset(len),
822                         }
823                     );
824                 }
825             }
826         }
827     }
828 
829     #[test]
skip_header_extension()830     fn skip_header_extension() {
831         use crate::ip_number::*;
832         {
833             let buffer: [u8; 8] = [0; 8];
834             let mut cursor = Cursor::new(&buffer);
835             assert_eq!(
836                 Ipv6Header::skip_header_extension(&mut cursor, ICMP).unwrap(),
837                 ICMP
838             );
839             assert_eq!(0, cursor.position());
840         }
841         {
842             let buffer: [u8; 8] = [0; 8];
843             let mut cursor = Cursor::new(&buffer);
844             assert_eq!(
845                 Ipv6Header::skip_header_extension(&mut cursor, IPV6_HOP_BY_HOP).unwrap(),
846                 IpNumber(0)
847             );
848             assert_eq!(8, cursor.position());
849         }
850         {
851             #[rustfmt::skip]
852             let buffer: [u8; 8 * 3] = [
853                 4, 2, 0, 0, 0, 0, 0, 0,
854                 0, 0, 0, 0, 0, 0, 0, 0,
855                 0, 0, 0, 0, 0, 0, 0, 0,
856             ];
857             let mut cursor = Cursor::new(&buffer);
858             assert_eq!(
859                 Ipv6Header::skip_header_extension(&mut cursor, IPV6_ROUTE).unwrap(),
860                 IpNumber(4)
861             );
862             assert_eq!(8 * 3, cursor.position());
863         }
864         {
865             //fragmentation header has a fixed size -> the 2 should be ignored
866             #[rustfmt::skip]
867             let buffer: [u8; 8 * 3] = [
868                 4, 2, 0, 0, 0, 0, 0, 0,
869                 0, 0, 0, 0, 0, 0, 0, 0,
870                 0, 0, 0, 0, 0, 0, 0, 0,
871             ];
872             let mut cursor = Cursor::new(&buffer);
873             assert_eq!(
874                 Ipv6Header::skip_header_extension(&mut cursor, IPV6_FRAG).unwrap(),
875                 IpNumber(4)
876             );
877             assert_eq!(8, cursor.position());
878         }
879     }
880 
881     proptest! {
882         #[test]
883         fn skip_all_header_extensions(
884             hop_by_hop in ipv6_raw_ext_any(),
885             dst_opt1 in ipv6_raw_ext_any(),
886             route in ipv6_raw_ext_any(),
887             frag in ipv6_fragment_any(),
888             auth in ip_auth_any(),
889             dst_opt2 in ipv6_raw_ext_any(),
890             mobility in ipv6_raw_ext_any(),
891             hip in ipv6_raw_ext_any(),
892             shim6 in ipv6_raw_ext_any()
893         ) {
894             // no extension header
895             {
896                 let mut cursor = Cursor::new(&[]);
897                 let next = Ipv6Header::skip_all_header_extensions(&mut cursor, UDP).unwrap();
898                 assert_eq!(UDP, next);
899                 assert_eq!(0, cursor.position());
900             }
901 
902             // setup a buffer with all extension headers present
903             let buffer = {
904                 let mut buffer = ArrayVec::<u8, {
905                     Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
906                 }>::new();
907 
908                 // based on RFC 8200 4.1. Extension Header Order
909                 // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
910                 //
911                 // IPV6_HOP_BY_HOP,
912                 // IPV6_DEST_OPTIONS,
913                 // IPV6_ROUTE,
914                 // IPV6_FRAG,
915                 // AUTH,
916                 // IPV6_DEST_OPTIONS,
917                 // MOBILITY,
918                 // HIP,
919                 // SHIM6,
920 
921                 let mut hop_by_hop = hop_by_hop.clone();
922                 hop_by_hop.next_header = IPV6_DEST_OPTIONS;
923                 buffer.extend(hop_by_hop.to_bytes());
924 
925                 let mut dst_opt1 = dst_opt1.clone();
926                 dst_opt1.next_header = IPV6_ROUTE;
927                 buffer.extend(dst_opt1.to_bytes());
928 
929                 let mut route = route.clone();
930                 route.next_header = IPV6_FRAG;
931                 buffer.extend(route.to_bytes());
932 
933                 let mut frag = frag.clone();
934                 frag.next_header = AUTH;
935                 buffer.extend(frag.to_bytes());
936 
937                 let mut auth = auth.clone();
938                 auth.next_header = IPV6_DEST_OPTIONS;
939                 buffer.extend(auth.to_bytes());
940 
941                 let mut dst_opt2 = dst_opt2.clone();
942                 dst_opt2.next_header = MOBILITY;
943                 buffer.extend(dst_opt2.to_bytes());
944 
945                 let mut mobility = mobility.clone();
946                 mobility.next_header = HIP;
947                 buffer.extend(mobility.to_bytes());
948 
949                 let mut hip = hip.clone();
950                 hip.next_header = SHIM6;
951                 buffer.extend(hip.to_bytes());
952 
953                 let mut shim6 = shim6.clone();
954                 shim6.next_header = TCP;
955                 buffer.extend(shim6.to_bytes());
956 
957                 buffer
958             };
959 
960             // ok skip case with all extension headers
961             {
962                 let mut cursor = Cursor::new(&buffer);
963                 let last = Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP).unwrap();
964                 assert_eq!(last, TCP);
965                 assert_eq!(cursor.position(), buffer.len() as u64);
966             }
967 
968             // length error
969             for len in 0..buffer.len() {
970                 let mut cursor = Cursor::new(&buffer[..len]);
971                 assert!(
972                     Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP)
973                     .is_err()
974                 );
975             }
976         }
977     }
978 
979     proptest! {
980         #[test]
981         fn write(header in ipv6_any()) {
982             let mut buffer = [0u8;Ipv6Header::LEN];
983             let len = {
984                 let mut cursor = Cursor::new(&mut buffer[..]);
985                 header.write(&mut cursor).unwrap();
986                 cursor.position() as usize
987             };
988             assert_eq!(len, header.header_len());
989             assert_eq!(
990                 Ipv6Header::from_slice(&buffer[..len]).unwrap().0,
991                 header
992             );
993         }
994     }
995 
996     proptest! {
997         #[test]
998         fn source_addr(header in ipv6_any()) {
999             assert_eq!(
1000                 header.source_addr().octets(),
1001                 header.source
1002             );
1003         }
1004     }
1005 
1006     proptest! {
1007         #[test]
1008         fn destination_addr(header in ipv6_any()) {
1009             assert_eq!(
1010                 header.destination_addr().octets(),
1011                 header.destination
1012             );
1013         }
1014     }
1015 
1016     proptest! {
1017         #[test]
1018         fn to_bytes(header in ipv6_any()) {
1019             let bytes = header.to_bytes();
1020             assert_eq!(
1021                 Ipv6Header::from_slice(&bytes).unwrap().0,
1022                 header
1023             );
1024         }
1025     }
1026 }
1027