1use crate::{err::ValueTooBigError, *};
2
3#[derive(Clone, Debug, Eq, PartialEq, Default)]
5pub struct Ipv6Header {
6 pub traffic_class: u8,
7 pub flow_label: Ipv6FlowLabel,
9 pub payload_length: u16,
11 pub next_header: IpNumber,
15 pub hop_limit: u8,
17 pub source: [u8; 16],
19 pub destination: [u8; 16],
21}
22
23impl Ipv6Header {
24 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 #[deprecated(since = "0.10.1", note = "Renamed to `Ipv6Header::from_slice`")]
32 #[inline]
33 pub fn read_from_slice(
34 slice: &[u8],
35 ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> {
36 Ipv6Header::from_slice(slice)
37 }
38
39 #[inline]
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 #[cfg(feature = "std")]
69 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 #[cfg(feature = "std")]
86 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 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 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 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 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 _ => 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 pub fn is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool {
183 use crate::ip_number::*;
184 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 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 #[cfg(feature = "std")]
223 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 _ => return Ok(next_header),
248 };
249
250 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 #[cfg(feature = "std")]
268 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 #[cfg(feature = "std")]
286 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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 #[inline]
293 pub fn source_addr(&self) -> core::net::Ipv6Addr {
294 core::net::Ipv6Addr::from(self.source)
295 }
296
297 #[inline]
299 pub fn destination_addr(&self) -> core::net::Ipv6Addr {
300 core::net::Ipv6Addr::from(self.destination)
301 }
302
303 #[inline]
308 pub fn header_len(&self) -> usize {
309 Ipv6Header::LEN
310 }
311
312 pub fn set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>> {
314 use crate::err::ValueType;
315 const MAX_PAYLOAD_LENGTH: usize = u16::MAX as usize;
317 if MAX_PAYLOAD_LENGTH < size {
318 return Err(ValueTooBigError {
319 actual: size,
320 max_allowed: MAX_PAYLOAD_LENGTH,
321 value_type: ValueType::Ipv6PayloadLength,
322 });
323 }
324
325 self.payload_length = size as u16;
326 Ok(())
327 }
328
329 pub fn set_ecn(&mut self, ecn: IpEcn) {
331 self.traffic_class = (self.traffic_class & 0b1111_1100) | (ecn.value() & 0b11);
332 }
333
334 pub fn ecn(&self) -> IpEcn {
336 unsafe { IpEcn::new_unchecked(self.traffic_class & 0b0000_0011) }
338 }
339
340 pub fn set_dscp(&mut self, dscp: IpDscp) {
342 self.traffic_class =
343 (self.traffic_class & 0b0000_0011) | ((dscp.value() << 2) & 0b1111_1100);
344 }
345
346 pub fn dscp(&self) -> IpDscp {
348 unsafe { IpDscp::new_unchecked((self.traffic_class >> 2) & 0b0011_1111) }
351 }
352
353 #[rustfmt::skip]
356 pub fn to_bytes(&self) -> [u8;Ipv6Header::LEN] {
357 let flow_label_be = self.flow_label.value().to_be_bytes();
359 let payload_len_be = self.payload_length.to_be_bytes();
360
361 [
362 (6 << 4) | (self.traffic_class >> 4),
363 (self.traffic_class << 4) | flow_label_be[1],
364 flow_label_be[2],
365 flow_label_be[3],
366 payload_len_be[0],
367 payload_len_be[1],
368 self.next_header.0,
369 self.hop_limit,
370 self.source[0], self.source[1], self.source[2], self.source[3],
371 self.source[4], self.source[5], self.source[6], self.source[7],
372 self.source[8], self.source[9], self.source[10], self.source[11],
373 self.source[12], self.source[13], self.source[14], self.source[15],
374 self.destination[0], self.destination[1], self.destination[2], self.destination[3],
375 self.destination[4], self.destination[5], self.destination[6], self.destination[7],
376 self.destination[8], self.destination[9], self.destination[10], self.destination[11],
377 self.destination[12], self.destination[13], self.destination[14], self.destination[15],
378 ]
379 }
380}
381
382#[cfg(test)]
383mod test {
384 use crate::{
385 err::ipv6::HeaderError::*, err::ipv6::HeaderSliceError::*, ip_number::*, test_gens::*, *,
386 };
387 use alloc::format;
388 use arrayvec::ArrayVec;
389 use proptest::*;
390 use std::io::Cursor;
391
392 #[test]
393 fn default() {
394 let header: Ipv6Header = Default::default();
395 assert_eq!(0, header.traffic_class);
396 assert_eq!(0, header.flow_label.value());
397 assert_eq!(0, header.payload_length);
398 assert_eq!(255, header.next_header.0);
399 assert_eq!(0, header.hop_limit);
400 assert_eq!([0u8; 16], header.source);
401 assert_eq!([0u8; 16], header.destination);
402 }
403
404 #[test]
405 fn debug() {
406 let header: Ipv6Header = Default::default();
407 assert_eq!(
408 format!("{:?}", header),
409 format!(
410 "Ipv6Header {{ traffic_class: {}, flow_label: {:?}, payload_length: {}, next_header: {:?}, hop_limit: {}, source: {:?}, destination: {:?} }}",
411 header.traffic_class,
412 header.flow_label,
413 header.payload_length,
414 header.next_header,
415 header.hop_limit,
416 header.source,
417 header.destination
418 )
419 );
420 }
421
422 proptest! {
423 #[test]
424 fn clone_eq(header in ipv6_any()) {
425 assert_eq!(header.clone(), header);
426 }
427 }
428
429 proptest! {
430 #[test]
431 #[allow(deprecated)]
432 fn read_from_slice(
433 header in ipv6_any(),
434 bad_version in 0..=0b1111u8
435 ) {
436 {
438 let bytes = header.to_bytes();
439 let (actual, rest) = Ipv6Header::read_from_slice(&bytes).unwrap();
440 assert_eq!(header, actual);
441 assert_eq!(rest, &[]);
442 }
443
444 if bad_version != 6 {
446 let mut bytes = header.to_bytes();
447 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
449
450 assert_eq!(
451 Ipv6Header::read_from_slice(&bytes).unwrap_err(),
452 Content(UnexpectedVersion{ version_number: bad_version })
453 );
454 }
455
456 {
458 let bytes = header.to_bytes();
459 for len in 0..bytes.len() {
460 assert_eq!(
461 Ipv6Header::read_from_slice(&bytes[..len])
462 .unwrap_err(),
463 Len(err::LenError{
464 required_len: Ipv6Header::LEN,
465 len: len,
466 len_source: LenSource::Slice,
467 layer: err::Layer::Ipv6Header,
468 layer_start_offset: 0,
469 })
470 );
471 }
472 }
473 }
474 }
475
476 proptest! {
477 #[test]
478 fn set_dscp(
479 header in ipv6_any(),
480 dscp in ip_dscp_any()
481 ) {
482 let mut header = header;
483 assert_eq!(header.dscp(), IpDscp::try_new(header.traffic_class >> 2).unwrap());
484 header.set_dscp(dscp);
485 assert_eq!(dscp, IpDscp::try_new(header.traffic_class >> 2).unwrap());
486 assert_eq!(header.dscp(), dscp);
487 }
488 }
489
490 proptest! {
491 #[test]
492 fn set_ecn(
493 header in ipv6_any(),
494 ecn in ip_ecn_any()
495 ) {
496 let mut header = header;
497 assert_eq!(header.ecn(), IpEcn::try_new(header.traffic_class & 0b11).unwrap());
498 header.set_ecn(ecn);
499 assert_eq!(ecn, IpEcn::try_new(header.traffic_class & 0b11).unwrap());
500 assert_eq!(header.ecn(), ecn);
501 }
502 }
503
504 proptest! {
505 #[test]
506 fn from_slice(
507 header in ipv6_any(),
508 bad_version in 0..=0b1111u8
509 ) {
510 {
512 let bytes = header.to_bytes();
513 let (actual, rest) = Ipv6Header::from_slice(&bytes).unwrap();
514 assert_eq!(header, actual);
515 assert_eq!(rest, &[]);
516 }
517
518 if bad_version != 6 {
520 let mut bytes = header.to_bytes();
521 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
523
524 assert_eq!(
525 Ipv6Header::from_slice(&bytes).unwrap_err(),
526 Content(UnexpectedVersion{ version_number: bad_version })
527 );
528 }
529
530 {
532 let bytes = header.to_bytes();
533 for len in 0..bytes.len() {
534 assert_eq!(
535 Ipv6Header::from_slice(&bytes[..len])
536 .unwrap_err(),
537 Len(err::LenError{
538 required_len: Ipv6Header::LEN,
539 len: len,
540 len_source: LenSource::Slice,
541 layer: err::Layer::Ipv6Header,
542 layer_start_offset: 0,
543 })
544 );
545 }
546 }
547 }
548 }
549
550 proptest! {
551 #[test]
552 fn read(
553 header in ipv6_any(),
554 bad_version in 0..=0b1111u8
555 ) {
556 use err::ipv6::HeaderError::*;
557
558 {
560 let bytes = header.to_bytes();
561 let mut cursor = Cursor::new(&bytes[..]);
562 let actual = Ipv6Header::read(&mut cursor).unwrap();
563 assert_eq!(header, actual);
564 assert_eq!(cursor.position(), bytes.len() as u64);
565 }
566
567 if bad_version != 6 {
569 let mut bytes = header.to_bytes();
570 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
572
573 let mut cursor = Cursor::new(&bytes[..]);
574 assert_eq!(
575 Ipv6Header::read(&mut cursor)
576 .unwrap_err()
577 .content_error()
578 .unwrap(),
579 UnexpectedVersion {
580 version_number: bad_version,
581 }
582 );
583 }
584
585 {
587 let bytes = header.to_bytes();
588 for len in 0..bytes.len() {
589 let mut cursor = Cursor::new(&bytes[..len]);
590 assert!(Ipv6Header::read(&mut cursor).is_err());
591 }
592 }
593 }
594 }
595
596 proptest! {
597 #[test]
598 fn read_without_version(header in ipv6_any()) {
599 {
601 let bytes = header.to_bytes();
602 let mut cursor = Cursor::new(&bytes[1..]);
603 let actual = Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).unwrap();
604 assert_eq!(header, actual);
605 assert_eq!(cursor.position(), bytes.len() as u64 - 1);
606 }
607
608 {
610 let bytes = header.to_bytes();
611 for len in 1..bytes.len() {
612 let mut cursor = Cursor::new(&bytes[1..len]);
613 assert!(Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).is_err());
614 }
615 }
616 }
617 }
618
619 proptest! {
620 #[test]
621 fn skip_header_extension_in_slice(
622 generic in ipv6_raw_ext_any(),
623 frag in ipv6_fragment_any(),
624 auth in ip_auth_any()
625 ) {
626 const GENERICS: [IpNumber;7] = [
627 IPV6_HOP_BY_HOP,
628 IPV6_DEST_OPTIONS,
629 IPV6_ROUTE,
630 IPV6_DEST_OPTIONS,
631 MOBILITY,
632 HIP,
633 SHIM6,
634 ];
635
636 for g in GENERICS {
638 let bytes = generic.to_bytes();
639 {
641 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, g).unwrap();
642 assert_eq!(next, generic.next_header);
643 assert_eq!(rest, &[]);
644 }
645 for len in 0..bytes.len() {
647 assert_eq!(
648 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], g).unwrap_err(),
649 err::LenError {
650 required_len: if len < 2 {
651 2
652 } else {
653 bytes.len()
654 },
655 len: len,
656 len_source: LenSource::Slice,
657 layer: err::Layer::Ipv6ExtHeader,
658 layer_start_offset: 0,
659 }
660 );
661 }
662 }
663 {
665 let bytes = frag.to_bytes();
666 {
668 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, IPV6_FRAG).unwrap();
669 assert_eq!(next, frag.next_header);
670 assert_eq!(rest, &[]);
671 }
672 for len in 0..bytes.len() {
674 assert_eq!(
675 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], IPV6_FRAG).unwrap_err(),
676 err::LenError {
677 required_len: if len < 2 {
678 2
679 } else {
680 bytes.len()
681 },
682 len: len,
683 len_source: LenSource::Slice,
684 layer: err::Layer::Ipv6ExtHeader,
685 layer_start_offset: 0,
686 }
687 );
688 }
689 }
690
691 {
693 let bytes = auth.to_bytes();
694 {
696 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, AUTH).unwrap();
697 assert_eq!(next, auth.next_header);
698 assert_eq!(rest, &[]);
699 }
700 for len in 0..bytes.len() {
702 assert_eq!(
703 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], AUTH).unwrap_err(),
704 err::LenError {
705 required_len: if len < 2 {
706 2
707 } else {
708 bytes.len()
709 },
710 len: len,
711 len_source: LenSource::Slice,
712 layer: err::Layer::Ipv6ExtHeader,
713 layer_start_offset: 0,
714 }
715 );
716 }
717 }
718 }
719 }
720
721 #[test]
722 fn is_skippable_header_extension() {
723 for i in 0..0xffu8 {
724 let expected = match IpNumber(i) {
725 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_FRAG | AUTH | IPV6_DEST_OPTIONS | MOBILITY
726 | HIP | SHIM6 => true,
727 _ => false,
728 };
729 assert_eq!(
730 expected,
731 Ipv6Header::is_skippable_header_extension(IpNumber(i))
732 );
733 }
734 }
735
736 proptest! {
737 #[test]
738 fn skip_all_header_extensions_in_slice(
739 hop_by_hop in ipv6_raw_ext_any(),
740 dst_opt1 in ipv6_raw_ext_any(),
741 route in ipv6_raw_ext_any(),
742 frag in ipv6_fragment_any(),
743 auth in ip_auth_any(),
744 dst_opt2 in ipv6_raw_ext_any(),
745 mobility in ipv6_raw_ext_any(),
746 hip in ipv6_raw_ext_any(),
747 shim6 in ipv6_raw_ext_any()
748 ) {
749 {
751 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&[], UDP).unwrap();
752 assert_eq!(UDP, next);
753 assert_eq!(rest, &[]);
754 }
755
756 let buffer = {
758 let mut buffer = ArrayVec::<u8, {
759 Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
760 }>::new();
761
762 let mut hop_by_hop = hop_by_hop.clone();
776 hop_by_hop.next_header = IPV6_DEST_OPTIONS;
777 buffer.extend(hop_by_hop.to_bytes());
778
779 let mut dst_opt1 = dst_opt1.clone();
780 dst_opt1.next_header = IPV6_ROUTE;
781 buffer.extend(dst_opt1.to_bytes());
782
783 let mut route = route.clone();
784 route.next_header = IPV6_FRAG;
785 buffer.extend(route.to_bytes());
786
787 let mut frag = frag.clone();
788 frag.next_header = AUTH;
789 buffer.extend(frag.to_bytes());
790
791 let mut auth = auth.clone();
792 auth.next_header = IPV6_DEST_OPTIONS;
793 buffer.extend(auth.to_bytes());
794
795 let mut dst_opt2 = dst_opt2.clone();
796 dst_opt2.next_header = MOBILITY;
797 buffer.extend(dst_opt2.to_bytes());
798
799 let mut mobility = mobility.clone();
800 mobility.next_header = HIP;
801 buffer.extend(mobility.to_bytes());
802
803 let mut hip = hip.clone();
804 hip.next_header = SHIM6;
805 buffer.extend(hip.to_bytes());
806
807 let mut shim6 = shim6.clone();
808 shim6.next_header = TCP;
809 buffer.extend(shim6.to_bytes());
810
811 buffer
812 };
813
814 {
816 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&buffer, IPV6_HOP_BY_HOP).unwrap();
817 assert_eq!(next, TCP);
818 assert_eq!(rest, &[]);
819 }
820
821 {
823 let len_ranges: [usize;9] = [
824 hop_by_hop.header_len(),
825 dst_opt1.header_len(),
826 route.header_len(),
827 frag.header_len(),
828 auth.header_len(),
829 dst_opt2.header_len(),
830 mobility.header_len(),
831 hip.header_len(),
832 shim6.header_len()
833 ];
834 let get_expected = |len: usize| -> usize{
835 let mut curr = 0;
836 for next in &len_ranges {
837 if len < curr {
838 break;
839 }
840 if len < curr + 2 {
841 curr += 2;
842 break;
843 }
844 curr += next;
845 }
846 curr
847 };
848
849 let get_offset = |len: usize| -> usize{
850 let mut curr = 0;
851 for next in &len_ranges {
852 if len < curr + next {
853 break;
854 }
855 curr += next;
856 }
857 curr
858 };
859
860 for len in 0..buffer.len() {
861 assert_eq!(
862 Ipv6Header::skip_all_header_extensions_in_slice(&buffer[..len], IPV6_HOP_BY_HOP)
863 .unwrap_err(),
864 err::LenError {
865 required_len: get_expected(len) - get_offset(len),
866 len: len - get_offset(len),
867 len_source: LenSource::Slice,
868 layer: err::Layer::Ipv6ExtHeader,
869 layer_start_offset: get_offset(len),
870 }
871 );
872 }
873 }
874 }
875 }
876
877 #[test]
878 fn skip_header_extension() {
879 use crate::ip_number::*;
880 {
881 let buffer: [u8; 8] = [0; 8];
882 let mut cursor = Cursor::new(&buffer);
883 assert_eq!(
884 Ipv6Header::skip_header_extension(&mut cursor, ICMP).unwrap(),
885 ICMP
886 );
887 assert_eq!(0, cursor.position());
888 }
889 {
890 let buffer: [u8; 8] = [0; 8];
891 let mut cursor = Cursor::new(&buffer);
892 assert_eq!(
893 Ipv6Header::skip_header_extension(&mut cursor, IPV6_HOP_BY_HOP).unwrap(),
894 IpNumber(0)
895 );
896 assert_eq!(8, cursor.position());
897 }
898 {
899 #[rustfmt::skip]
900 let buffer: [u8; 8 * 3] = [
901 4, 2, 0, 0, 0, 0, 0, 0,
902 0, 0, 0, 0, 0, 0, 0, 0,
903 0, 0, 0, 0, 0, 0, 0, 0,
904 ];
905 let mut cursor = Cursor::new(&buffer);
906 assert_eq!(
907 Ipv6Header::skip_header_extension(&mut cursor, IPV6_ROUTE).unwrap(),
908 IpNumber(4)
909 );
910 assert_eq!(8 * 3, cursor.position());
911 }
912 {
913 #[rustfmt::skip]
915 let buffer: [u8; 8 * 3] = [
916 4, 2, 0, 0, 0, 0, 0, 0,
917 0, 0, 0, 0, 0, 0, 0, 0,
918 0, 0, 0, 0, 0, 0, 0, 0,
919 ];
920 let mut cursor = Cursor::new(&buffer);
921 assert_eq!(
922 Ipv6Header::skip_header_extension(&mut cursor, IPV6_FRAG).unwrap(),
923 IpNumber(4)
924 );
925 assert_eq!(8, cursor.position());
926 }
927 }
928
929 proptest! {
930 #[test]
931 fn skip_all_header_extensions(
932 hop_by_hop in ipv6_raw_ext_any(),
933 dst_opt1 in ipv6_raw_ext_any(),
934 route in ipv6_raw_ext_any(),
935 frag in ipv6_fragment_any(),
936 auth in ip_auth_any(),
937 dst_opt2 in ipv6_raw_ext_any(),
938 mobility in ipv6_raw_ext_any(),
939 hip in ipv6_raw_ext_any(),
940 shim6 in ipv6_raw_ext_any()
941 ) {
942 {
944 let mut cursor = Cursor::new(&[]);
945 let next = Ipv6Header::skip_all_header_extensions(&mut cursor, UDP).unwrap();
946 assert_eq!(UDP, next);
947 assert_eq!(0, cursor.position());
948 }
949
950 let buffer = {
952 let mut buffer = ArrayVec::<u8, {
953 Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
954 }>::new();
955
956 let mut hop_by_hop = hop_by_hop.clone();
970 hop_by_hop.next_header = IPV6_DEST_OPTIONS;
971 buffer.extend(hop_by_hop.to_bytes());
972
973 let mut dst_opt1 = dst_opt1.clone();
974 dst_opt1.next_header = IPV6_ROUTE;
975 buffer.extend(dst_opt1.to_bytes());
976
977 let mut route = route.clone();
978 route.next_header = IPV6_FRAG;
979 buffer.extend(route.to_bytes());
980
981 let mut frag = frag.clone();
982 frag.next_header = AUTH;
983 buffer.extend(frag.to_bytes());
984
985 let mut auth = auth.clone();
986 auth.next_header = IPV6_DEST_OPTIONS;
987 buffer.extend(auth.to_bytes());
988
989 let mut dst_opt2 = dst_opt2.clone();
990 dst_opt2.next_header = MOBILITY;
991 buffer.extend(dst_opt2.to_bytes());
992
993 let mut mobility = mobility.clone();
994 mobility.next_header = HIP;
995 buffer.extend(mobility.to_bytes());
996
997 let mut hip = hip.clone();
998 hip.next_header = SHIM6;
999 buffer.extend(hip.to_bytes());
1000
1001 let mut shim6 = shim6.clone();
1002 shim6.next_header = TCP;
1003 buffer.extend(shim6.to_bytes());
1004
1005 buffer
1006 };
1007
1008 {
1010 let mut cursor = Cursor::new(&buffer);
1011 let last = Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP).unwrap();
1012 assert_eq!(last, TCP);
1013 assert_eq!(cursor.position(), buffer.len() as u64);
1014 }
1015
1016 for len in 0..buffer.len() {
1018 let mut cursor = Cursor::new(&buffer[..len]);
1019 assert!(
1020 Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP)
1021 .is_err()
1022 );
1023 }
1024 }
1025 }
1026
1027 proptest! {
1028 #[test]
1029 fn write(header in ipv6_any()) {
1030 let mut buffer = [0u8;Ipv6Header::LEN];
1031 let len = {
1032 let mut cursor = Cursor::new(&mut buffer[..]);
1033 header.write(&mut cursor).unwrap();
1034 cursor.position() as usize
1035 };
1036 assert_eq!(len, header.header_len());
1037 assert_eq!(
1038 Ipv6Header::from_slice(&buffer[..len]).unwrap().0,
1039 header
1040 );
1041 }
1042 }
1043
1044 proptest! {
1045 #[test]
1046 fn source_addr(header in ipv6_any()) {
1047 assert_eq!(
1048 header.source_addr().octets(),
1049 header.source
1050 );
1051 }
1052 }
1053
1054 proptest! {
1055 #[test]
1056 fn destination_addr(header in ipv6_any()) {
1057 assert_eq!(
1058 header.destination_addr().octets(),
1059 header.destination
1060 );
1061 }
1062 }
1063
1064 proptest! {
1065 #[test]
1066 fn to_bytes(header in ipv6_any()) {
1067 let bytes = header.to_bytes();
1068 assert_eq!(
1069 Ipv6Header::from_slice(&bytes).unwrap().0,
1070 header
1071 );
1072 }
1073 }
1074}