1use core::convert::Infallible as Never;
12use core::marker::PhantomData;
13
14use byteorder::{ByteOrder, NetworkEndian};
15use packet::records::options::{
16 AlignedOptionBuilder, LengthEncoding, OptionBuilder, OptionLayout, OptionParseErr,
17 OptionParseLayout,
18};
19use packet::records::{
20 ParsedRecord, RecordParseResult, Records, RecordsContext, RecordsImpl, RecordsImplLayout,
21 RecordsRawImpl,
22};
23use packet::{BufferView, BufferViewMut};
24use zerocopy::byteorder::network_endian::U16;
25
26use crate::ip::{FragmentOffset, IpProto, Ipv6ExtHdrType, Ipv6Proto};
27
28use crate::ipv6::{IPV6_FIXED_HDR_LEN, NEXT_HEADER_OFFSET};
29
30pub(crate) const IPV6_FRAGMENT_EXT_HDR_LEN: usize = 8;
32
33#[allow(missing_docs)]
35#[derive(Debug)]
36pub enum Ipv6ExtensionHeader<'a> {
37 HopByHopOptions { options: HopByHopOptionsData<'a> },
38 Routing { routing_data: RoutingData<'a> },
39 Fragment { fragment_data: FragmentData },
40 DestinationOptions { options: DestinationOptionsData<'a> },
41}
42
43#[allow(missing_docs)]
49#[derive(Debug, PartialEq, Eq)]
50pub(super) enum Ipv6ExtensionHeaderParsingError {
51 ErroneousHeaderField { pointer: u32, must_send_icmp: bool },
57 UnrecognizedNextHeader { pointer: u32, must_send_icmp: bool },
58 UnrecognizedOption { pointer: u32, must_send_icmp: bool, action: ExtensionHeaderOptionAction },
59 BufferExhausted,
60 MalformedData,
61}
62
63impl From<Never> for Ipv6ExtensionHeaderParsingError {
64 fn from(err: Never) -> Ipv6ExtensionHeaderParsingError {
65 match err {}
66 }
67}
68
69#[derive(Debug, Clone)]
71pub(super) struct Ipv6ExtensionHeaderParsingContext {
72 pub(super) next_header: u8,
76
77 iter: bool,
79
80 headers_parsed: usize,
82
83 pub(super) position: usize,
85
86 pub(super) next_header_offset: usize,
88}
89
90impl Ipv6ExtensionHeaderParsingContext {
91 pub(super) fn new(next_header: u8) -> Ipv6ExtensionHeaderParsingContext {
94 Ipv6ExtensionHeaderParsingContext {
95 iter: false,
96 headers_parsed: 0,
97 next_header,
98 next_header_offset: NEXT_HEADER_OFFSET.into(),
99 position: IPV6_FIXED_HDR_LEN,
100 }
101 }
102}
103
104impl RecordsContext for Ipv6ExtensionHeaderParsingContext {
105 type Counter = ();
106
107 fn clone_for_iter(&self) -> Self {
108 let mut ret = self.clone();
109 ret.iter = true;
110 ret
111 }
112
113 fn counter_mut(&mut self) -> &mut () {
114 get_empty_tuple_mut_ref()
115 }
116}
117
118#[derive(Debug)]
120pub(super) struct Ipv6ExtensionHeaderImpl;
121
122impl Ipv6ExtensionHeaderImpl {
123 fn parse_next_hdr_and_len<'a, BV: BufferView<&'a [u8]>>(
129 data: &mut BV,
130 context: &mut Ipv6ExtensionHeaderParsingContext,
131 ) -> Result<u8, Ipv6ExtensionHeaderParsingError> {
132 let next_header =
133 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
134 let hdr_ext_len =
135 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
136
137 context.next_header = next_header;
138 context.next_header_offset = context.position;
139 context.position += 2;
140
141 Ok(hdr_ext_len)
142 }
143
144 fn parse_hop_by_hop_options<'a, BV: BufferView<&'a [u8]>>(
149 data: &mut BV,
150 context: &mut Ipv6ExtensionHeaderParsingContext,
151 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
152 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
153
154 let expected_len = (hdr_ext_len as usize) * 8 + 6;
160
161 let options = data
162 .take_front(expected_len)
163 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
164
165 let options_context = ExtensionHeaderOptionContext::new(context.position);
166 let options = Records::parse_with_context(options, options_context)
167 .map_err(ext_hdr_opt_err_to_ext_hdr_err)?;
168 let options = HopByHopOptionsData::new(options);
169
170 context.position += expected_len;
172 context.headers_parsed += 1;
173
174 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::HopByHopOptions { options }))
175 }
176
177 fn parse_routing<'a, BV: BufferView<&'a [u8]>>(
179 data: &mut BV,
180 context: &mut Ipv6ExtensionHeaderParsingContext,
181 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
182 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
183
184 let expected_len = (hdr_ext_len as usize) * 8 + 6;
190 let bytes = data
191 .take_front(expected_len)
192 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
193 let routing_data = RoutingData { bytes };
194
195 let segments_left = routing_data.segments_left();
196
197 if segments_left == 0 {
211 context.position += expected_len;
213 context.headers_parsed += 1;
214
215 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::Routing { routing_data }))
216 } else {
217 Err(Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
221 pointer: u32::try_from(context.position).unwrap(),
222 must_send_icmp: true,
223 })
224 }
225 }
226
227 fn parse_fragment<'a, BV: BufferView<&'a [u8]>>(
229 data: &mut BV,
230 context: &mut Ipv6ExtensionHeaderParsingContext,
231 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
232 if data.len() < 8 {
238 return Err(Ipv6ExtensionHeaderParsingError::BufferExhausted);
239 }
240
241 let _ = Self::parse_next_hdr_and_len(data, context)?;
245
246 context.position += 6;
248 context.headers_parsed += 1;
249
250 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::Fragment {
251 fragment_data: FragmentData { bytes: data.take_front(6).unwrap().try_into().unwrap() },
257 }))
258 }
259
260 fn parse_destination_options<'a, BV: BufferView<&'a [u8]>>(
262 data: &mut BV,
263 context: &mut Ipv6ExtensionHeaderParsingContext,
264 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
265 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
266
267 let expected_len = (hdr_ext_len as usize) * 8 + 6;
271
272 let options = data
273 .take_front(expected_len)
274 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
275
276 let options_context = ExtensionHeaderOptionContext::new(context.position);
277 let options = Records::parse_with_context(options, options_context)
278 .map_err(ext_hdr_opt_err_to_ext_hdr_err)?;
279 let options = DestinationOptionsData::new(options);
280
281 context.position += expected_len;
283 context.headers_parsed += 1;
284
285 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::DestinationOptions { options }))
286 }
287}
288
289impl RecordsImplLayout for Ipv6ExtensionHeaderImpl {
290 type Context = Ipv6ExtensionHeaderParsingContext;
291 type Error = Ipv6ExtensionHeaderParsingError;
292}
293
294impl RecordsImpl for Ipv6ExtensionHeaderImpl {
295 type Record<'a> = Ipv6ExtensionHeader<'a>;
296
297 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
298 data: &mut BV,
299 context: &mut Self::Context,
300 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
301 let expected_hdr = context.next_header;
302
303 match Ipv6ExtHdrType::from(expected_hdr) {
304 Ipv6ExtHdrType::HopByHopOptions => {
305 if context.headers_parsed == 0 {
306 Self::parse_hop_by_hop_options(data, context)
307 } else {
308 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
310 pointer: context.next_header_offset as u32,
311 must_send_icmp: false,
312 })
313 }
314 }
315 Ipv6ExtHdrType::Routing => Self::parse_routing(data, context),
316 Ipv6ExtHdrType::Fragment => Self::parse_fragment(data, context),
317 Ipv6ExtHdrType::DestinationOptions => Self::parse_destination_options(data, context),
318 Ipv6ExtHdrType::EncapsulatingSecurityPayload | Ipv6ExtHdrType::Authentication => {
319 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
331 pointer: context.next_header_offset as u32,
332 must_send_icmp: false,
335 })
336 }
337 Ipv6ExtHdrType::Other(_) if is_valid_next_header_upper_layer(expected_hdr) => {
338 Ok(ParsedRecord::Done)
341 }
342 Ipv6ExtHdrType::Other(_) => {
343 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
344 pointer: context.next_header_offset as u32,
345 must_send_icmp: false,
346 })
347 }
348 }
349 }
350}
351
352impl<'a> RecordsRawImpl<'a> for Ipv6ExtensionHeaderImpl {
353 fn parse_raw_with_context<BV: BufferView<&'a [u8]>>(
354 data: &mut BV,
355 context: &mut Self::Context,
356 ) -> Result<bool, Self::Error> {
357 let (next, skip) = match Ipv6ExtHdrType::from(context.next_header) {
358 Ipv6ExtHdrType::HopByHopOptions => {
359 if context.headers_parsed == 0 {
360 data.take_front(2)
363 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
364 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
365 } else {
366 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
368 pointer: context.next_header_offset as u32,
369 must_send_icmp: false,
370 });
371 }
372 }
373
374 Ipv6ExtHdrType::Routing | Ipv6ExtHdrType::DestinationOptions => {
375 data.take_front(2)
378 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
379 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
380 }
381 Ipv6ExtHdrType::Fragment => {
382 (
384 data.take_byte_front()
385 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?,
386 7,
387 )
388 }
389 Ipv6ExtHdrType::EncapsulatingSecurityPayload => {
390 return debug_err!(
394 Err(Ipv6ExtensionHeaderParsingError::MalformedData),
395 "ESP extension header not supported"
396 );
397 }
398 Ipv6ExtHdrType::Authentication => {
399 data.take_front(2)
403 .map(|x| (x[0], (x[1] as usize + 2) * 4 - 2))
404 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
405 }
406 Ipv6ExtHdrType::Other(next_header) if is_valid_next_header_upper_layer(next_header) => {
407 return Ok(false);
408 }
409
410 Ipv6ExtHdrType::Other(_) => {
411 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
412 pointer: context.next_header_offset as u32,
413 must_send_icmp: false,
414 });
415 }
416 };
417 let _: &[u8] =
418 data.take_front(skip).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
419 context.next_header = next;
420 context.next_header_offset = context.position;
421 context.position += skip;
422 context.headers_parsed += 1;
423 Ok(true)
424 }
425}
426
427#[derive(Debug)]
433pub struct HopByHopOptionsData<'a> {
434 options: Records<&'a [u8], HopByHopOptionsImpl>,
435}
436
437impl<'a> HopByHopOptionsData<'a> {
438 fn new(options: Records<&'a [u8], HopByHopOptionsImpl>) -> HopByHopOptionsData<'a> {
440 HopByHopOptionsData { options }
441 }
442
443 pub fn iter(&'a self) -> impl Iterator<Item = HopByHopOption<'a>> {
446 self.options.iter()
447 }
448}
449
450pub type HopByHopOption<'a> = ExtensionHeaderOption<HopByHopOptionData<'a>>;
452
453pub(super) type HopByHopOptionsImpl = ExtensionHeaderOptionImpl<HopByHopOptionDataImpl>;
456
457const HBH_OPTION_KIND_RTRALRT: u8 = 5;
461
462const HBH_OPTION_RTRALRT_LEN: usize = 2;
466
467#[allow(missing_docs)]
469#[derive(Debug, PartialEq, Eq, Clone)]
470pub enum HopByHopOptionData<'a> {
471 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
472 RouterAlert { data: u16 },
473}
474
475#[derive(Debug)]
477pub(super) struct HopByHopOptionDataImpl;
478
479impl ExtensionHeaderOptionDataImplLayout for HopByHopOptionDataImpl {
480 type Context = ();
481}
482
483impl ExtensionHeaderOptionDataImpl for HopByHopOptionDataImpl {
484 type OptionData<'a> = HopByHopOptionData<'a>;
485
486 fn parse_option<'a>(
487 kind: u8,
488 data: &'a [u8],
489 _context: &mut Self::Context,
490 allow_unrecognized: bool,
491 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
492 match kind {
493 HBH_OPTION_KIND_RTRALRT => {
494 if data.len() == HBH_OPTION_RTRALRT_LEN {
495 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::RouterAlert {
496 data: NetworkEndian::read_u16(data),
497 })
498 } else {
499 ExtensionHeaderOptionDataParseResult::ErrorAt(1)
502 }
503 }
504 _ => {
505 if allow_unrecognized {
506 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::Unrecognized {
507 kind,
508 len: data.len() as u8,
509 data,
510 })
511 } else {
512 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
513 }
514 }
515 }
516 }
517}
518
519impl OptionLayout for HopByHopOptionsImpl {
520 type KindLenField = u8;
521 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
522}
523
524impl OptionParseLayout for HopByHopOptionsImpl {
525 type Error = OptionParseErr;
526 const END_OF_OPTIONS: Option<u8> = Some(0);
527 const NOP: Option<u8> = Some(1);
528}
529
530#[doc(hidden)]
536pub enum HopByHopOptionLayout {}
537
538impl OptionLayout for HopByHopOptionLayout {
539 type KindLenField = u8;
540 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
541}
542
543impl<'a> OptionBuilder for HopByHopOption<'a> {
544 type Layout = HopByHopOptionLayout;
545 fn serialized_len(&self) -> usize {
546 match self.data {
547 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_RTRALRT_LEN,
548 HopByHopOptionData::Unrecognized { len, .. } => len as usize,
549 }
550 }
551
552 fn option_kind(&self) -> u8 {
553 let action: u8 = self.action.into();
554 let mutable = self.mutable as u8;
555 let type_number = match self.data {
556 HopByHopOptionData::Unrecognized { kind, .. } => kind,
557 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_KIND_RTRALRT,
558 };
559 (action << 6) | (mutable << 5) | type_number
560 }
561
562 fn serialize_into(&self, mut buffer: &mut [u8]) {
563 match self.data {
564 HopByHopOptionData::Unrecognized { data, .. } => buffer.copy_from_slice(data),
565 HopByHopOptionData::RouterAlert { data } => {
566 (&mut buffer).write_obj_front(&U16::new(data)).unwrap()
569 }
570 }
571 }
572}
573
574impl<'a> AlignedOptionBuilder for HopByHopOption<'a> {
575 fn alignment_requirement(&self) -> (usize, usize) {
576 match self.data {
577 HopByHopOptionData::RouterAlert { .. } => (2, 0),
580 _ => (1, 0),
581 }
582 }
583
584 fn serialize_padding(buf: &mut [u8], length: usize) {
585 assert!(length <= buf.len());
586 assert!(length <= (core::u8::MAX as usize) + 2);
587
588 #[allow(clippy::comparison_chain)]
589 if length == 1 {
590 buf[0] = 0
592 } else if length > 1 {
593 buf[0] = 1;
595 buf[1] = (length - 2) as u8;
596 #[allow(clippy::needless_range_loop)]
597 for i in 2..length {
598 buf[i] = 0
599 }
600 }
601 }
602}
603
604#[derive(Debug)]
624pub struct RoutingData<'a> {
625 bytes: &'a [u8],
626}
627
628#[derive(Debug, PartialEq, Eq)]
630pub enum RoutingType {}
631
632#[derive(Debug, PartialEq, Eq)]
634pub enum RoutingTypeParseError {
635 UnsupportedType(u8),
638}
639
640impl TryFrom<u8> for RoutingType {
641 type Error = RoutingTypeParseError;
642
643 fn try_from(value: u8) -> Result<Self, Self::Error> {
644 Err(RoutingTypeParseError::UnsupportedType(value))
645 }
646}
647
648impl<'a> RoutingData<'a> {
649 pub fn routing_type(&self) -> Result<RoutingType, RoutingTypeParseError> {
651 debug_assert!(self.bytes.len() >= 6);
652 RoutingType::try_from(self.bytes[0])
653 }
654
655 pub fn segments_left(&self) -> u8 {
657 debug_assert!(self.bytes.len() >= 6);
658 self.bytes[1]
659 }
660}
661
662#[derive(Debug, Copy, Clone)]
678pub struct FragmentData {
679 bytes: [u8; 6],
680}
681
682impl FragmentData {
683 pub fn fragment_offset(&self) -> FragmentOffset {
685 FragmentOffset::new_with_msb(U16::from_bytes([self.bytes[0], self.bytes[1]]).get())
686 }
687
688 pub fn m_flag(&self) -> bool {
690 (self.bytes[1] & 0x1) == 0x01
691 }
692
693 pub fn identification(&self) -> u32 {
695 NetworkEndian::read_u32(&self.bytes[2..6])
696 }
697}
698
699#[derive(Debug)]
705pub struct DestinationOptionsData<'a> {
706 options: Records<&'a [u8], DestinationOptionsImpl>,
707}
708
709impl<'a> DestinationOptionsData<'a> {
710 fn new(options: Records<&'a [u8], DestinationOptionsImpl>) -> DestinationOptionsData<'a> {
712 DestinationOptionsData { options }
713 }
714
715 pub fn iter(&'a self) -> impl Iterator<Item = DestinationOption<'a>> {
718 self.options.iter()
719 }
720}
721
722pub type DestinationOption<'a> = ExtensionHeaderOption<DestinationOptionData<'a>>;
724
725pub(super) type DestinationOptionsImpl = ExtensionHeaderOptionImpl<DestinationOptionDataImpl>;
728
729#[allow(missing_docs)]
731#[derive(Debug)]
732pub enum DestinationOptionData<'a> {
733 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
734}
735
736#[derive(Debug)]
738pub(super) struct DestinationOptionDataImpl;
739
740impl ExtensionHeaderOptionDataImplLayout for DestinationOptionDataImpl {
741 type Context = ();
742}
743
744impl ExtensionHeaderOptionDataImpl for DestinationOptionDataImpl {
745 type OptionData<'a> = DestinationOptionData<'a>;
746
747 fn parse_option<'a>(
748 kind: u8,
749 data: &'a [u8],
750 _context: &mut Self::Context,
751 allow_unrecognized: bool,
752 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
753 if allow_unrecognized {
754 ExtensionHeaderOptionDataParseResult::Ok(DestinationOptionData::Unrecognized {
755 kind,
756 len: data.len() as u8,
757 data,
758 })
759 } else {
760 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
761 }
762 }
763}
764
765#[derive(Debug, Clone)]
771pub(super) struct ExtensionHeaderOptionContext<C: Sized + Clone> {
772 options_parsed: usize,
774
775 position: usize,
777
778 specific_context: C,
780}
781
782impl<C: Sized + Clone + Default> ExtensionHeaderOptionContext<C> {
783 fn new(offset: usize) -> Self {
784 ExtensionHeaderOptionContext {
785 options_parsed: 0,
786 position: offset,
787 specific_context: C::default(),
788 }
789 }
790}
791
792impl<C: Sized + Clone> RecordsContext for ExtensionHeaderOptionContext<C> {
793 type Counter = ();
794
795 fn counter_mut(&mut self) -> &mut () {
796 get_empty_tuple_mut_ref()
797 }
798}
799
800pub(super) trait ExtensionHeaderOptionDataImplLayout {
802 type Context: RecordsContext;
805}
806
807#[derive(PartialEq, Eq, Debug)]
809pub enum ExtensionHeaderOptionDataParseResult<D> {
810 Ok(D),
812
813 ErrorAt(u32),
819
820 UnrecognizedKind,
822}
823
824pub(super) trait ExtensionHeaderOptionDataImpl: ExtensionHeaderOptionDataImplLayout {
826 type OptionData<'a>: Sized;
832
833 fn parse_option<'a>(
844 kind: u8,
845 data: &'a [u8],
846 context: &mut Self::Context,
847 allow_unrecognized: bool,
848 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>>;
849}
850
851#[derive(Debug)]
858pub(super) struct ExtensionHeaderOptionImpl<O>(PhantomData<O>);
859
860impl<O> ExtensionHeaderOptionImpl<O> {
861 const PAD1: u8 = 0;
862 const PADN: u8 = 1;
863}
864
865impl<O> RecordsImplLayout for ExtensionHeaderOptionImpl<O>
866where
867 O: ExtensionHeaderOptionDataImplLayout,
868{
869 type Error = ExtensionHeaderOptionParsingError;
870 type Context = ExtensionHeaderOptionContext<O::Context>;
871}
872
873impl<O> RecordsImpl for ExtensionHeaderOptionImpl<O>
874where
875 O: ExtensionHeaderOptionDataImpl,
876{
877 type Record<'a> = ExtensionHeaderOption<O::OptionData<'a>>;
878
879 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
880 data: &mut BV,
881 context: &mut Self::Context,
882 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
883 let kind = match data.take_byte_front() {
885 None => return Ok(ParsedRecord::Done),
886 Some(k) => k,
887 };
888
889 let action =
893 ExtensionHeaderOptionAction::try_from((kind >> 6) & 0x3).expect("Unexpected error");
894 let mutable = ((kind >> 5) & 0x1) == 0x1;
895 if kind == Self::PAD1 {
901 context.options_parsed += 1;
903 context.position += 1;
904
905 return Ok(ParsedRecord::Skipped);
906 }
907
908 let len =
909 data.take_byte_front().ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
910
911 let data = data
912 .take_front(len as usize)
913 .ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
914
915 if kind == Self::PADN {
917 context.options_parsed += 1;
919 context.position += 2 + (len as usize);
920
921 return Ok(ParsedRecord::Skipped);
922 }
923
924 match O::parse_option(
926 kind,
927 data,
928 &mut context.specific_context,
929 action == ExtensionHeaderOptionAction::SkipAndContinue,
930 ) {
931 ExtensionHeaderOptionDataParseResult::Ok(o) => {
932 context.options_parsed += 1;
934 context.position += 2 + (len as usize);
935
936 Ok(ParsedRecord::Parsed(ExtensionHeaderOption { action, mutable, data: o }))
937 }
938 ExtensionHeaderOptionDataParseResult::ErrorAt(offset) => {
939 Err(ExtensionHeaderOptionParsingError::ErroneousOptionField {
944 pointer: u32::try_from(context.position + offset as usize).unwrap(),
945 })
946 }
947 ExtensionHeaderOptionDataParseResult::UnrecognizedKind => {
948 match action {
950 ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
957 "Should never end up here since action was set to skip and continue"
958 ),
959 _ => Err(ExtensionHeaderOptionParsingError::UnrecognizedOption {
970 pointer: u32::try_from(context.position).unwrap(),
971 action,
972 }),
973 }
974 }
975 }
976 }
977}
978
979#[allow(missing_docs)]
981#[derive(Debug, PartialEq, Eq)]
982pub(crate) enum ExtensionHeaderOptionParsingError {
983 ErroneousOptionField { pointer: u32 },
984 UnrecognizedOption { pointer: u32, action: ExtensionHeaderOptionAction },
985 BufferExhausted,
986}
987
988impl From<Never> for ExtensionHeaderOptionParsingError {
989 fn from(err: Never) -> ExtensionHeaderOptionParsingError {
990 match err {}
991 }
992}
993
994#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1000pub enum ExtensionHeaderOptionAction {
1001 SkipAndContinue,
1004
1005 DiscardPacket,
1008
1009 DiscardPacketSendIcmp,
1015
1016 DiscardPacketSendIcmpNoMulticast,
1022}
1023
1024impl TryFrom<u8> for ExtensionHeaderOptionAction {
1025 type Error = ();
1026
1027 fn try_from(value: u8) -> Result<Self, ()> {
1028 match value {
1029 0 => Ok(ExtensionHeaderOptionAction::SkipAndContinue),
1030 1 => Ok(ExtensionHeaderOptionAction::DiscardPacket),
1031 2 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmp),
1032 3 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast),
1033 _ => Err(()),
1034 }
1035 }
1036}
1037
1038impl From<ExtensionHeaderOptionAction> for u8 {
1039 fn from(a: ExtensionHeaderOptionAction) -> u8 {
1040 match a {
1041 ExtensionHeaderOptionAction::SkipAndContinue => 0,
1042 ExtensionHeaderOptionAction::DiscardPacket => 1,
1043 ExtensionHeaderOptionAction::DiscardPacketSendIcmp => 2,
1044 ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => 3,
1045 }
1046 }
1047}
1048
1049#[derive(PartialEq, Eq, Debug, Clone)]
1055pub struct ExtensionHeaderOption<O> {
1056 pub action: ExtensionHeaderOptionAction,
1058
1059 pub mutable: bool,
1065
1066 pub data: O,
1068}
1069
1070pub(super) fn is_valid_next_header_upper_layer(next_header: u8) -> bool {
1079 match Ipv6Proto::from(next_header) {
1080 Ipv6Proto::Proto(IpProto::Tcp)
1081 | Ipv6Proto::Proto(IpProto::Udp)
1082 | Ipv6Proto::Icmpv6
1083 | Ipv6Proto::NoNextHeader => true,
1084 Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => false,
1085 }
1086}
1087
1088fn ext_hdr_opt_err_to_ext_hdr_err(
1094 err: ExtensionHeaderOptionParsingError,
1095) -> Ipv6ExtensionHeaderParsingError {
1096 match err {
1097 ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer } => {
1098 Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1099 pointer: pointer,
1100 must_send_icmp: false,
1105 }
1106 }
1107 ExtensionHeaderOptionParsingError::UnrecognizedOption { pointer, action } => {
1108 Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1109 pointer: pointer,
1110 must_send_icmp: true,
1111 action,
1112 }
1113 }
1114 ExtensionHeaderOptionParsingError::BufferExhausted => {
1115 Ipv6ExtensionHeaderParsingError::BufferExhausted
1116 }
1117 }
1118}
1119
1120fn get_empty_tuple_mut_ref<'a>() -> &'a mut () {
1121 let bytes: &mut [u8] = &mut [];
1123 zerocopy::Ref::into_mut(zerocopy::Ref::<_, ()>::from_bytes(bytes).unwrap())
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128 use packet::records::{AlignedRecordSequenceBuilder, RecordBuilder};
1129
1130 use crate::ip::Ipv4Proto;
1131 use crate::ipv6::IPV6_FIXED_HDR_LEN;
1132
1133 use super::*;
1134
1135 #[test]
1136 fn test_is_valid_next_header_upper_layer() {
1137 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1139 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1140
1141 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1143 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1144 }
1145
1146 #[test]
1147 fn test_hop_by_hop_options() {
1148 let buffer = [0; 10];
1150 let mut context = ExtensionHeaderOptionContext::new(10);
1151 let options =
1152 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1153 .unwrap();
1154 assert_eq!(options.iter().count(), 0);
1155 assert_eq!(context.position, 20);
1156 assert_eq!(context.options_parsed, 10);
1157
1158 #[rustfmt::skip]
1160 let buffer = [
1161 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1165 let mut context = ExtensionHeaderOptionContext::new(1);
1166 let options =
1167 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1168 .unwrap();
1169 assert_eq!(options.iter().count(), 0);
1170 assert_eq!(context.position, 14);
1171 assert_eq!(context.options_parsed, 3);
1172
1173 #[rustfmt::skip]
1176 let buffer = [
1177 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1181 let mut context = ExtensionHeaderOptionContext::new(1);
1182 let options =
1183 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1184 .unwrap();
1185 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1186 assert_eq!(options.len(), 1);
1187 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1188 assert_eq!(context.position, 13);
1189 assert_eq!(context.options_parsed, 3);
1190 }
1191
1192 #[test]
1193 fn test_hop_by_hop_options_err() {
1194 #[rustfmt::skip]
1196 let buffer = [
1197 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1201 let mut context = ExtensionHeaderOptionContext::new(5);
1202 assert_eq!(
1203 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1204 .expect_err("Parsed successfully when we were short 2 bytes"),
1205 ExtensionHeaderOptionParsingError::BufferExhausted
1206 );
1207 assert_eq!(context.position, 8);
1208 assert_eq!(context.options_parsed, 2);
1209
1210 #[rustfmt::skip]
1212 let buffer = [
1213 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1217 let mut context = ExtensionHeaderOptionContext::new(5);
1218 assert_eq!(
1219 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1220 .expect_err("Parsed successfully when we had an unrecognized option type"),
1221 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1222 pointer: 8,
1223 action: ExtensionHeaderOptionAction::DiscardPacket,
1224 }
1225 );
1226 assert_eq!(context.position, 8);
1227 assert_eq!(context.options_parsed, 1);
1228
1229 #[rustfmt::skip]
1232 let buffer = [
1233 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1238 let mut context = ExtensionHeaderOptionContext::new(5);
1239 assert_eq!(
1240 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1241 .expect_err("Parsed successfully when we had an unrecognized option type"),
1242 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1243 pointer: 8,
1244 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1245 }
1246 );
1247 assert_eq!(context.position, 8);
1248 assert_eq!(context.options_parsed, 1);
1249
1250 #[rustfmt::skip]
1253 let buffer = [
1254 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1259 let mut context = ExtensionHeaderOptionContext::new(5);
1260 assert_eq!(
1261 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1262 .expect_err("Parsed successfully when we had an unrecognized option type"),
1263 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1264 pointer: 8,
1265 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1266 }
1267 );
1268 assert_eq!(context.position, 8);
1269 assert_eq!(context.options_parsed, 1);
1270
1271 #[rustfmt::skip]
1273 let buffer = [
1274 0xC0,
1277 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1280 let mut context = ExtensionHeaderOptionContext::new(5);
1281 assert_eq!(
1282 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1283 .expect_err("Parsed successfully when we had Pad1 with upper bits set"),
1284 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1285 pointer: 5,
1286 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1287 }
1288 );
1289 assert_eq!(context.position, 5);
1290 assert_eq!(context.options_parsed, 0);
1291
1292 #[rustfmt::skip]
1294 let buffer = [
1295 0, 0xC1, 0,
1299 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1301 let mut context = ExtensionHeaderOptionContext::new(5);
1302 assert_eq!(
1303 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1304 .expect_err("Parsed successfully when we had Pad2 with upper bits set"),
1305 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1306 pointer: 6,
1307 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1308 }
1309 );
1310 assert_eq!(context.position, 6);
1311 assert_eq!(context.options_parsed, 1);
1312
1313 #[rustfmt::skip]
1315 let buffer = [
1316 0, 1, 0, 0xC1, 8, 0, 0, 0, 0, 0, 0, 0, 0,
1321 ];
1322 let mut context = ExtensionHeaderOptionContext::new(5);
1323 assert_eq!(
1324 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1325 .expect_err("Parsed successfully when we had PadN with upper bits set"),
1326 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1327 pointer: 8,
1328 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1329 }
1330 );
1331 assert_eq!(context.position, 8);
1332 assert_eq!(context.options_parsed, 2);
1333 }
1334
1335 #[test]
1336 fn test_destination_options() {
1337 let buffer = [0; 10];
1339 let mut context = ExtensionHeaderOptionContext::new(5);
1340 let options =
1341 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1342 .unwrap();
1343 assert_eq!(options.iter().count(), 0);
1344 assert_eq!(context.position, 15);
1345 assert_eq!(context.options_parsed, 10);
1346
1347 #[rustfmt::skip]
1349 let buffer = [
1350 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1354 let mut context = ExtensionHeaderOptionContext::new(5);
1355 let options =
1356 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1357 .unwrap();
1358 assert_eq!(options.iter().count(), 0);
1359 assert_eq!(context.position, 18);
1360 assert_eq!(context.options_parsed, 3);
1361
1362 #[rustfmt::skip]
1365 let buffer = [
1366 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1370 let mut context = ExtensionHeaderOptionContext::new(5);
1371 let options =
1372 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1373 .unwrap();
1374 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1375 assert_eq!(options.len(), 1);
1376 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1377 assert_eq!(context.position, 17);
1378 assert_eq!(context.options_parsed, 3);
1379 }
1380
1381 #[test]
1382 fn test_destination_options_err() {
1383 #[rustfmt::skip]
1385 let buffer = [
1386 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1390 let mut context = ExtensionHeaderOptionContext::new(5);
1391 assert_eq!(
1392 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1393 .expect_err("Parsed successfully when we were short 2 bytes"),
1394 ExtensionHeaderOptionParsingError::BufferExhausted
1395 );
1396 assert_eq!(context.position, 8);
1397 assert_eq!(context.options_parsed, 2);
1398
1399 #[rustfmt::skip]
1401 let buffer = [
1402 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1406 let mut context = ExtensionHeaderOptionContext::new(5);
1407 assert_eq!(
1408 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1409 .expect_err("Parsed successfully when we had an unrecognized option type"),
1410 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1411 pointer: 8,
1412 action: ExtensionHeaderOptionAction::DiscardPacket,
1413 }
1414 );
1415 assert_eq!(context.position, 8);
1416 assert_eq!(context.options_parsed, 1);
1417
1418 #[rustfmt::skip]
1421 let buffer = [
1422 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1427 let mut context = ExtensionHeaderOptionContext::new(5);
1428 assert_eq!(
1429 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1430 .expect_err("Parsed successfully when we had an unrecognized option type"),
1431 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1432 pointer: 8,
1433 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1434 }
1435 );
1436 assert_eq!(context.position, 8);
1437 assert_eq!(context.options_parsed, 1);
1438
1439 #[rustfmt::skip]
1442 let buffer = [
1443 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1448 let mut context = ExtensionHeaderOptionContext::new(5);
1449 assert_eq!(
1450 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1451 .expect_err("Parsed successfully when we had an unrecognized option type"),
1452 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1453 pointer: 8,
1454 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1455 }
1456 );
1457 assert_eq!(context.position, 8);
1458 assert_eq!(context.options_parsed, 1);
1459 }
1460
1461 #[test]
1462 fn test_hop_by_hop_options_ext_hdr() {
1463 let context =
1466 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1467 #[rustfmt::skip]
1468 let buffer = [
1469 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1474 let ext_hdrs =
1475 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1476 .unwrap();
1477 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1478 assert_eq!(ext_hdrs.len(), 1);
1479 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1480 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1482 assert_eq!(options.len(), 1);
1483 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1484 } else {
1485 panic!("Should have matched HopByHopOptions {:?}", ext_hdrs[0]);
1486 }
1487 }
1488
1489 #[test]
1490 fn test_hop_by_hop_options_ext_hdr_err() {
1491 let context =
1495 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1496 #[rustfmt::skip]
1497 let buffer = [
1498 255, 0, 1, 4, 0, 0, 0, 0, ];
1502 let error =
1503 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1504 .expect_err("Parsed successfully when the next header was invalid");
1505 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1506 error
1507 {
1508 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1509 assert!(!must_send_icmp);
1510 } else {
1511 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1512 }
1513
1514 let context =
1516 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1517 #[rustfmt::skip]
1518 let buffer = [
1519 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1524 let error =
1525 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1526 .expect_err("Parsed successfully with an unrecognized option type");
1527 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1528 pointer,
1529 must_send_icmp,
1530 action,
1531 } = error
1532 {
1533 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1534 assert!(must_send_icmp);
1535 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1536 } else {
1537 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1538 }
1539
1540 let context =
1542 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1543 #[rustfmt::skip]
1544 let buffer = [
1545 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1550 let error =
1551 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1552 .expect_err("Parsed successfully with an unrecognized option type");
1553 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1554 pointer,
1555 must_send_icmp,
1556 action,
1557 } = error
1558 {
1559 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1560 assert!(must_send_icmp);
1561 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1562 } else {
1563 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1564 }
1565
1566 let context =
1568 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1569 #[rustfmt::skip]
1570 let buffer = [
1571 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1577 let error =
1578 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1579 .expect_err("Parsed successfully with an unrecognized option type");
1580 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1581 pointer,
1582 must_send_icmp,
1583 action,
1584 } = error
1585 {
1586 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1587 assert!(must_send_icmp);
1588 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1589 } else {
1590 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1591 }
1592
1593 let context =
1595 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1596 #[rustfmt::skip]
1597 let buffer = [
1598 IpProto::Tcp.into(), 0, 5, 3, 0, 0, 0, 0, ];
1603 let error =
1604 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1605 .expect_err(
1606 "Should fail to parse the header because one of the option is malformed",
1607 );
1608 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, .. } = error {
1609 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 3);
1610 } else {
1611 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1612 }
1613 }
1614
1615 #[test]
1616 fn test_routing_ext_hdr() {
1617 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1619 #[rustfmt::skip]
1620 let buffer = [
1621 IpProto::Tcp.into(), 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1628 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1629
1630 ];
1631 let ext_hdrs =
1632 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1633 .unwrap();
1634 let results: Vec<_> = ext_hdrs.iter().collect();
1635 assert_eq!(results.len(), 1);
1636 if let Ipv6ExtensionHeader::Routing { routing_data } = &results[0] {
1637 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1638 assert_eq!(routing_data.segments_left(), 0);
1639 } else {
1640 panic!("Should have matched with RoutingExtensionHeader");
1641 }
1642 }
1643
1644 #[test]
1645 fn test_routing_ext_hdr_err() {
1646 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1650 #[rustfmt::skip]
1651 let buffer = [
1652 IpProto::Tcp.into(), 4, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1659 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1660 ];
1661 let error =
1662 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1663 .expect_err("Parsed successfully when the routing type was set to 0");
1664 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1665 error
1666 {
1667 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1668 assert!(must_send_icmp);
1669 } else {
1670 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1671 }
1672
1673 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1675 #[rustfmt::skip]
1676 let buffer = [
1677 255, 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1684 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1685
1686 ];
1687 let error =
1688 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1689 .expect_err("Parsed successfully when the next header was invalid");
1690 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1691 error
1692 {
1693 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1694 assert!(!must_send_icmp);
1695 } else {
1696 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1697 }
1698
1699 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1701 #[rustfmt::skip]
1702 let buffer = [
1703 IpProto::Tcp.into(), 4, 255, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1710 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1711
1712 ];
1713 let error =
1714 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1715 .expect_err("Parsed successfully with an unrecognized routing type");
1716 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1717 error
1718 {
1719 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1721 assert!(must_send_icmp);
1722 } else {
1723 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1724 }
1725 }
1726
1727 #[test]
1728 fn test_fragment_ext_hdr() {
1729 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1731 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1732 let identification: u32 = 3266246449;
1733 #[rustfmt::skip]
1734 let buffer = [
1735 IpProto::Tcp.into(), 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1741 ((identification >> 16) & 0xFF) as u8,
1742 ((identification >> 8) & 0xFF) as u8,
1743 (identification & 0xFF) as u8,
1744 ];
1745 let ext_hdrs =
1746 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1747 .unwrap();
1748 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1749 assert_eq!(ext_hdrs.len(), 1);
1750
1751 if let Ipv6ExtensionHeader::Fragment { fragment_data } = &ext_hdrs[0] {
1752 assert_eq!(fragment_data.fragment_offset().into_raw(), 5063);
1753 assert_eq!(fragment_data.m_flag(), true);
1754 assert_eq!(fragment_data.identification(), 3266246449);
1755 } else {
1756 panic!("Should have matched Fragment: {:?}", &ext_hdrs[0]);
1757 }
1758 }
1759
1760 #[test]
1761 fn test_fragment_ext_hdr_err() {
1762 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1766 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1767 let identification: u32 = 3266246449;
1768 #[rustfmt::skip]
1769 let buffer = [
1770 255, 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1776 ((identification >> 16) & 0xFF) as u8,
1777 ((identification >> 8) & 0xFF) as u8,
1778 (identification & 0xFF) as u8,
1779 ];
1780 let error =
1781 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1782 .expect_err("Parsed successfully when the next header was invalid");
1783 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1784 error
1785 {
1786 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1787 assert!(!must_send_icmp);
1788 } else {
1789 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1790 }
1791 }
1792
1793 #[test]
1794 fn test_no_next_header_ext_hdr() {
1795 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6Proto::NoNextHeader.into());
1797 #[rustfmt::skip]
1798 let buffer = [0, 0, 0, 0,];
1799 let ext_hdrs =
1800 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1801 .unwrap();
1802 assert_eq!(ext_hdrs.iter().count(), 0);
1803 }
1804
1805 #[test]
1806 fn test_destination_options_ext_hdr() {
1807 let context =
1810 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1811 #[rustfmt::skip]
1812 let buffer = [
1813 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1818 let ext_hdrs =
1819 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1820 .unwrap();
1821 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1822 assert_eq!(ext_hdrs.len(), 1);
1823 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[0] {
1824 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1826 assert_eq!(options.len(), 1);
1827 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1828 } else {
1829 panic!("Should have matched DestinationOptions: {:?}", &ext_hdrs[0]);
1830 }
1831 }
1832
1833 #[test]
1834 fn test_destination_options_ext_hdr_err() {
1835 let context =
1837 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1838
1839 #[rustfmt::skip]
1841 let buffer = [
1842 255, 0, 1, 4, 0, 0, 0, 0, ];
1846 let error =
1847 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1848 .expect_err("Parsed successfully when the next header was invalid");
1849 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1850 error
1851 {
1852 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1853 assert!(!must_send_icmp);
1854 } else {
1855 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1856 }
1857
1858 let context =
1860 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1861 #[rustfmt::skip]
1862 let buffer = [
1863 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1868 let error =
1869 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1870 .expect_err("Parsed successfully with an unrecognized option type");
1871 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1872 pointer,
1873 must_send_icmp,
1874 action,
1875 } = error
1876 {
1877 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1878 assert!(must_send_icmp);
1879 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1880 } else {
1881 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1882 }
1883
1884 let context =
1886 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1887 #[rustfmt::skip]
1888 let buffer = [
1889 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1894 let error =
1895 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1896 .expect_err("Parsed successfully with an unrecognized option type");
1897 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1898 pointer,
1899 must_send_icmp,
1900 action,
1901 } = error
1902 {
1903 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1904 assert!(must_send_icmp);
1905 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1906 } else {
1907 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1908 }
1909
1910 let context =
1912 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1913 #[rustfmt::skip]
1914 let buffer = [
1915 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1921 let error =
1922 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1923 .expect_err("Parsed successfully with an unrecognized option type");
1924 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1925 pointer,
1926 must_send_icmp,
1927 action,
1928 } = error
1929 {
1930 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1931 assert!(must_send_icmp);
1932 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1933 } else {
1934 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1935 }
1936 }
1937
1938 #[test]
1939 fn test_multiple_ext_hdrs() {
1940 let context =
1942 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1943 #[rustfmt::skip]
1944 let buffer = [
1945 Ipv6ExtHdrType::Routing.into(), 0, 0, 1, 0, 1, 1, 0, Ipv6ExtHdrType::DestinationOptions.into(), 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1960 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1961
1962 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1970 let ext_hdrs =
1971 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1972 .unwrap();
1973
1974 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1975 assert_eq!(ext_hdrs.len(), 3);
1976
1977 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1979 assert_eq!(options.iter().count(), 0);
1981 } else {
1982 panic!("Should have matched HopByHopOptions: {:?}", &ext_hdrs[0]);
1983 }
1984
1985 if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1987 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1988 assert_eq!(routing_data.segments_left(), 0);
1989 } else {
1990 panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1991 }
1992
1993 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
1995 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1997 assert_eq!(options.len(), 1);
1998 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1999 } else {
2000 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[2]);
2001 }
2002 }
2003
2004 #[test]
2005 fn test_multiple_ext_hdrs_errs() {
2006 let context =
2010 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2011 #[rustfmt::skip]
2012 let buffer = [
2013 Ipv6ExtHdrType::Routing.into(), 0, 0, 1, 0, 1, 1, 0, 255, 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2028 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2029
2030 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
2038 let error =
2039 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2040 .expect_err("Parsed successfully when the next header was invalid");
2041 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2042 error
2043 {
2044 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
2045 assert!(!must_send_icmp);
2046 } else {
2047 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2048 }
2049
2050 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
2052 #[rustfmt::skip]
2053 let buffer = [
2054 Ipv6ExtHdrType::HopByHopOptions.into(), 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2062 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2063
2064 Ipv6ExtHdrType::DestinationOptions.into(), 0, 0, 1, 0, 1, 1, 0, IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
2079 let error =
2080 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2081 .expect_err("Parsed successfully when a hop by hop extension header was not the fist extension header");
2082 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2083 error
2084 {
2085 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
2086 assert!(!must_send_icmp);
2087 } else {
2088 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2089 }
2090
2091 let context =
2094 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2095 #[rustfmt::skip]
2096 let buffer = [
2097 Ipv6ExtHdrType::DestinationOptions.into(), 0, 0, 1, 0, 1, 1, 0, IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
2112 let error =
2113 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2114 .expect_err("Parsed successfully with an unrecognized destination option type");
2115 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
2116 pointer,
2117 must_send_icmp,
2118 action,
2119 } = error
2120 {
2121 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 16);
2122 assert!(must_send_icmp);
2123 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
2124 } else {
2125 panic!("Should have matched with UnrecognizedOption: {:?}", error);
2126 }
2127 }
2128
2129 #[test]
2130 fn test_serialize_hbh_router_alert() {
2131 let mut buffer = [0u8; 4];
2132 let option = HopByHopOption {
2133 action: ExtensionHeaderOptionAction::SkipAndContinue,
2134 mutable: false,
2135 data: HopByHopOptionData::RouterAlert { data: 0 },
2136 };
2137 <HopByHopOption<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
2138 assert_eq!(&buffer[..], &[5, 2, 0, 0]);
2139 }
2140
2141 #[test]
2142 fn test_parse_hbh_router_alert() {
2143 let context = ExtensionHeaderOptionContext::new(0);
2145 let buffer = [5, 2, 0, 0];
2146
2147 let options =
2148 Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context).unwrap();
2149 let rtralrt = options.iter().next().unwrap();
2150 assert!(!rtralrt.mutable);
2151 assert_eq!(rtralrt.action, ExtensionHeaderOptionAction::SkipAndContinue);
2152 assert_eq!(rtralrt.data, HopByHopOptionData::RouterAlert { data: 0 });
2153
2154 let context = ExtensionHeaderOptionContext::new(5);
2157 let buffer = [0xC5, 2, 0, 0];
2160
2161 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2162 .expect_err("UnrecognizedOption should have been returned");
2163 assert_eq!(
2164 error,
2165 ExtensionHeaderOptionParsingError::UnrecognizedOption {
2166 pointer: 5,
2167 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast
2168 }
2169 );
2170
2171 let result = <HopByHopOptionDataImpl as ExtensionHeaderOptionDataImpl>::parse_option(
2173 5,
2174 &buffer[1..],
2175 &mut (),
2176 false,
2177 );
2178 assert_eq!(result, ExtensionHeaderOptionDataParseResult::ErrorAt(1));
2179
2180 let context = ExtensionHeaderOptionContext::new(5);
2181 let buffer = [5, 3, 0, 0, 0];
2182
2183 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2184 .expect_err(
2185 "Parsing a malformed option with recognized kind but with wrong data should fail",
2186 );
2187 assert_eq!(error, ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer: 6 });
2188 }
2189
2190 fn trivial_hbh_options(lengths: &[Option<usize>]) -> Vec<HopByHopOption<'static>> {
2197 static ZEROES: [u8; 16] = [0u8; 16];
2198 lengths
2199 .iter()
2200 .map(|l| HopByHopOption {
2201 mutable: false,
2202 action: ExtensionHeaderOptionAction::SkipAndContinue,
2203 data: match l {
2204 Some(l) => HopByHopOptionData::Unrecognized {
2205 kind: 1,
2206 len: (*l - 2) as u8,
2207 data: &ZEROES[0..*l - 2],
2208 },
2209 None => HopByHopOptionData::RouterAlert { data: 0 },
2210 },
2211 })
2212 .collect()
2213 }
2214
2215 #[test]
2216 fn test_aligned_records_serializer() {
2217 for i in 2..12 {
2219 let options = trivial_hbh_options(&[Some(i), None]);
2220 let ser = AlignedRecordSequenceBuilder::<
2221 ExtensionHeaderOption<HopByHopOptionData<'_>>,
2222 _,
2223 >::new(2, options.iter());
2224 let mut buf = [0u8; 16];
2225 ser.serialize_into(&mut buf[0..16]);
2226 let base = (i + 1) & !1;
2227 assert_eq!(&buf[base..base + 4], &[5, 2, 0, 0]);
2229 }
2230 }
2231}