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
28pub(crate) const IPV6_FRAGMENT_EXT_HDR_LEN: usize = 8;
30
31#[derive(Debug)]
33pub struct Ipv6ExtensionHeader<'a> {
34 pub(super) next_header: u8,
37 data: Ipv6ExtensionHeaderData<'a>,
38}
39
40impl<'a> Ipv6ExtensionHeader<'a> {
41 pub fn data(&self) -> &Ipv6ExtensionHeaderData<'a> {
43 &self.data
44 }
45
46 pub fn into_data(self) -> Ipv6ExtensionHeaderData<'a> {
48 self.data
49 }
50}
51
52#[allow(missing_docs)]
54#[derive(Debug)]
55pub enum Ipv6ExtensionHeaderData<'a> {
56 HopByHopOptions { options: HopByHopOptionsData<'a> },
57 Fragment { fragment_data: FragmentData<'a> },
58 DestinationOptions { options: DestinationOptionsData<'a> },
59}
60
61#[allow(missing_docs)]
67#[derive(Debug, PartialEq, Eq)]
68pub(super) enum Ipv6ExtensionHeaderParsingError {
69 ErroneousHeaderField {
75 pointer: u32,
76 must_send_icmp: bool,
77 header_len: usize,
78 },
79 UnrecognizedNextHeader {
80 pointer: u32,
81 must_send_icmp: bool,
82 header_len: usize,
83 },
84 UnrecognizedOption {
85 pointer: u32,
86 must_send_icmp: bool,
87 header_len: usize,
88 action: ExtensionHeaderOptionAction,
89 },
90 BufferExhausted,
91 MalformedData,
92}
93
94impl From<Never> for Ipv6ExtensionHeaderParsingError {
95 fn from(err: Never) -> Ipv6ExtensionHeaderParsingError {
96 match err {}
97 }
98}
99
100#[derive(Debug, Clone)]
102pub(super) struct Ipv6ExtensionHeaderParsingContext {
103 pub(super) next_header: u8,
107
108 iter: bool,
110
111 headers_parsed: usize,
113
114 pub(super) bytes_parsed: usize,
116}
117
118impl Ipv6ExtensionHeaderParsingContext {
119 pub(super) fn new(next_header: u8) -> Ipv6ExtensionHeaderParsingContext {
122 Ipv6ExtensionHeaderParsingContext {
123 iter: false,
124 headers_parsed: 0,
125 next_header,
126 bytes_parsed: 0,
127 }
128 }
129}
130
131impl RecordsContext for Ipv6ExtensionHeaderParsingContext {
132 type Counter = ();
133
134 fn clone_for_iter(&self) -> Self {
135 let mut ret = self.clone();
136 ret.iter = true;
137 ret
138 }
139
140 fn counter_mut(&mut self) -> &mut () {
141 get_empty_tuple_mut_ref()
142 }
143}
144
145#[derive(Debug)]
147pub(super) struct Ipv6ExtensionHeaderImpl;
148
149impl Ipv6ExtensionHeaderImpl {
150 fn valid_next_header(next_header: u8) -> bool {
152 is_valid_next_header(next_header, false)
156 }
157
158 fn get_next_hdr_and_len<'a, BV: BufferView<&'a [u8]>>(
165 data: &mut BV,
166 context: &Ipv6ExtensionHeaderParsingContext,
167 ) -> Result<(u8, u8), Ipv6ExtensionHeaderParsingError> {
168 let next_header =
169 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
170
171 if !Self::valid_next_header(next_header) {
176 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
177 pointer: context.bytes_parsed as u32,
178 must_send_icmp: false,
179 header_len: context.bytes_parsed,
180 });
181 }
182
183 let hdr_ext_len =
184 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
185
186 Ok((next_header, hdr_ext_len))
187 }
188
189 fn parse_hop_by_hop_options<'a, BV: BufferView<&'a [u8]>>(
194 data: &mut BV,
195 context: &mut Ipv6ExtensionHeaderParsingContext,
196 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
197 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
198
199 let expected_len = (hdr_ext_len as usize) * 8 + 6;
205
206 let options = data
207 .take_front(expected_len)
208 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
209
210 let options_context = ExtensionHeaderOptionContext::new();
211 let options = Records::parse_with_context(options, options_context).map_err(|e| {
212 ext_hdr_opt_err_to_ext_hdr_err(
223 u32::try_from(context.bytes_parsed + 2).unwrap(),
224 context.bytes_parsed,
225 e,
226 )
227 })?;
228 let options = HopByHopOptionsData::new(options);
229
230 context.next_header = next_header;
232 context.headers_parsed += 1;
233 context.bytes_parsed += 2 + expected_len;
234
235 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
236 next_header,
237 data: Ipv6ExtensionHeaderData::HopByHopOptions { options },
238 }))
239 }
240
241 fn parse_routing<'a, BV: BufferView<&'a [u8]>>(
243 data: &mut BV,
244 context: &mut Ipv6ExtensionHeaderParsingContext,
245 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
246 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
249 let routing_data =
250 data.take_front(2).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
251 let segments_left = routing_data[1];
252
253 if segments_left == 0 {
265 let expected_len = (hdr_ext_len as usize) * 8 + 4;
269 let _: &[u8] = data
270 .take_front(expected_len)
271 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
272
273 context.next_header = next_header;
275 context.headers_parsed += 1;
276 context.bytes_parsed += expected_len;
277
278 Ok(ParsedRecord::Skipped)
279 } else {
280 Err(Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
284 pointer: (context.bytes_parsed as u32) + 2,
285 must_send_icmp: true,
286 header_len: context.bytes_parsed,
287 })
288 }
289 }
290
291 fn parse_fragment<'a, BV: BufferView<&'a [u8]>>(
293 data: &mut BV,
294 context: &mut Ipv6ExtensionHeaderParsingContext,
295 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
296 if data.len() < 8 {
302 return Err(Ipv6ExtensionHeaderParsingError::BufferExhausted);
303 }
304
305 let (next_header, _) = Self::get_next_hdr_and_len(data, context)?;
309
310 context.next_header = next_header;
312 context.headers_parsed += 1;
313 context.bytes_parsed += 8;
314
315 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
316 next_header,
317 data: Ipv6ExtensionHeaderData::Fragment {
318 fragment_data: FragmentData { bytes: data.take_front(6).unwrap() },
319 },
320 }))
321 }
322
323 fn parse_destination_options<'a, BV: BufferView<&'a [u8]>>(
325 data: &mut BV,
326 context: &mut Ipv6ExtensionHeaderParsingContext,
327 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
328 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
329
330 let expected_len = (hdr_ext_len as usize) * 8 + 6;
334
335 let options = data
336 .take_front(expected_len)
337 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
338
339 let options_context = ExtensionHeaderOptionContext::new();
340 let options = Records::parse_with_context(options, options_context).map_err(|e| {
341 ext_hdr_opt_err_to_ext_hdr_err(
352 u32::try_from(context.bytes_parsed + 2).unwrap(),
353 context.bytes_parsed,
354 e,
355 )
356 })?;
357 let options = DestinationOptionsData::new(options);
358
359 context.next_header = next_header;
361 context.headers_parsed += 1;
362 context.bytes_parsed += 2 + expected_len;
363
364 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
365 next_header,
366 data: Ipv6ExtensionHeaderData::DestinationOptions { options },
367 }))
368 }
369}
370
371impl RecordsImplLayout for Ipv6ExtensionHeaderImpl {
372 type Context = Ipv6ExtensionHeaderParsingContext;
373 type Error = Ipv6ExtensionHeaderParsingError;
374}
375
376impl RecordsImpl for Ipv6ExtensionHeaderImpl {
377 type Record<'a> = Ipv6ExtensionHeader<'a>;
378
379 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
380 data: &mut BV,
381 context: &mut Self::Context,
382 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
383 let expected_hdr = context.next_header;
384
385 match Ipv6ExtHdrType::from(expected_hdr) {
386 Ipv6ExtHdrType::HopByHopOptions => Self::parse_hop_by_hop_options(data, context),
387 Ipv6ExtHdrType::Routing => Self::parse_routing(data, context),
388 Ipv6ExtHdrType::Fragment => Self::parse_fragment(data, context),
389 Ipv6ExtHdrType::DestinationOptions => Self::parse_destination_options(data, context),
390 Ipv6ExtHdrType::EncapsulatingSecurityPayload | Ipv6ExtHdrType::Authentication => {
391 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
403 pointer: u32::MAX,
407 header_len: 0,
408 must_send_icmp: false,
411 })
412 }
413 Ipv6ExtHdrType::Other(_) => {
414 if is_valid_next_header_upper_layer(expected_hdr) {
415 Ok(ParsedRecord::Done)
418 } else {
419 unreachable!(
427 "Should never try parsing an extension header with an unrecognized type"
428 );
429 }
430 }
431 }
432 }
433}
434
435impl<'a> RecordsRawImpl<'a> for Ipv6ExtensionHeaderImpl {
436 fn parse_raw_with_context<BV: BufferView<&'a [u8]>>(
437 data: &mut BV,
438 context: &mut Self::Context,
439 ) -> Result<bool, Self::Error> {
440 if is_valid_next_header_upper_layer(context.next_header) {
441 Ok(false)
442 } else {
443 let (next, skip) = match Ipv6ExtHdrType::from(context.next_header) {
444 Ipv6ExtHdrType::HopByHopOptions
445 | Ipv6ExtHdrType::Routing
446 | Ipv6ExtHdrType::DestinationOptions
447 | Ipv6ExtHdrType::Other(_) => {
448 data.take_front(2)
454 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
455 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
456 }
457 Ipv6ExtHdrType::Fragment => {
458 (
460 data.take_byte_front()
461 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?,
462 7,
463 )
464 }
465 Ipv6ExtHdrType::EncapsulatingSecurityPayload => {
466 return debug_err!(
470 Err(Ipv6ExtensionHeaderParsingError::MalformedData),
471 "ESP extension header not supported"
472 );
473 }
474 Ipv6ExtHdrType::Authentication => {
475 data.take_front(2)
479 .map(|x| (x[0], (x[1] as usize + 2) * 4 - 2))
480 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
481 }
482 };
483 let _: &[u8] =
484 data.take_front(skip).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
485 context.next_header = next;
486 Ok(true)
487 }
488 }
489}
490
491#[derive(Debug)]
497pub struct HopByHopOptionsData<'a> {
498 options: Records<&'a [u8], HopByHopOptionsImpl>,
499}
500
501impl<'a> HopByHopOptionsData<'a> {
502 fn new(options: Records<&'a [u8], HopByHopOptionsImpl>) -> HopByHopOptionsData<'a> {
504 HopByHopOptionsData { options }
505 }
506
507 pub fn iter(&'a self) -> impl Iterator<Item = HopByHopOption<'a>> {
510 self.options.iter()
511 }
512}
513
514pub type HopByHopOption<'a> = ExtensionHeaderOption<HopByHopOptionData<'a>>;
516
517pub(super) type HopByHopOptionsImpl = ExtensionHeaderOptionImpl<HopByHopOptionDataImpl>;
520
521const HBH_OPTION_KIND_RTRALRT: u8 = 5;
525
526const HBH_OPTION_RTRALRT_LEN: usize = 2;
530
531#[allow(missing_docs)]
533#[derive(Debug, PartialEq, Eq, Clone)]
534pub enum HopByHopOptionData<'a> {
535 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
536 RouterAlert { data: u16 },
537}
538
539#[derive(Debug)]
541pub(super) struct HopByHopOptionDataImpl;
542
543impl ExtensionHeaderOptionDataImplLayout for HopByHopOptionDataImpl {
544 type Context = ();
545}
546
547impl ExtensionHeaderOptionDataImpl for HopByHopOptionDataImpl {
548 type OptionData<'a> = HopByHopOptionData<'a>;
549
550 fn parse_option<'a>(
551 kind: u8,
552 data: &'a [u8],
553 _context: &mut Self::Context,
554 allow_unrecognized: bool,
555 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
556 match kind {
557 HBH_OPTION_KIND_RTRALRT => {
558 if data.len() == HBH_OPTION_RTRALRT_LEN {
559 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::RouterAlert {
560 data: NetworkEndian::read_u16(data),
561 })
562 } else {
563 ExtensionHeaderOptionDataParseResult::ErrorAt(1)
566 }
567 }
568 _ => {
569 if allow_unrecognized {
570 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::Unrecognized {
571 kind,
572 len: data.len() as u8,
573 data,
574 })
575 } else {
576 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
577 }
578 }
579 }
580 }
581}
582
583impl OptionLayout for HopByHopOptionsImpl {
584 type KindLenField = u8;
585 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
586}
587
588impl OptionParseLayout for HopByHopOptionsImpl {
589 type Error = OptionParseErr;
590 const END_OF_OPTIONS: Option<u8> = Some(0);
591 const NOP: Option<u8> = Some(1);
592}
593
594#[doc(hidden)]
600pub enum HopByHopOptionLayout {}
601
602impl OptionLayout for HopByHopOptionLayout {
603 type KindLenField = u8;
604 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
605}
606
607impl<'a> OptionBuilder for HopByHopOption<'a> {
608 type Layout = HopByHopOptionLayout;
609 fn serialized_len(&self) -> usize {
610 match self.data {
611 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_RTRALRT_LEN,
612 HopByHopOptionData::Unrecognized { len, .. } => len as usize,
613 }
614 }
615
616 fn option_kind(&self) -> u8 {
617 let action: u8 = self.action.into();
618 let mutable = self.mutable as u8;
619 let type_number = match self.data {
620 HopByHopOptionData::Unrecognized { kind, .. } => kind,
621 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_KIND_RTRALRT,
622 };
623 (action << 6) | (mutable << 5) | type_number
624 }
625
626 fn serialize_into(&self, mut buffer: &mut [u8]) {
627 match self.data {
628 HopByHopOptionData::Unrecognized { data, .. } => buffer.copy_from_slice(data),
629 HopByHopOptionData::RouterAlert { data } => {
630 (&mut buffer).write_obj_front(&U16::new(data)).unwrap()
633 }
634 }
635 }
636}
637
638impl<'a> AlignedOptionBuilder for HopByHopOption<'a> {
639 fn alignment_requirement(&self) -> (usize, usize) {
640 match self.data {
641 HopByHopOptionData::RouterAlert { .. } => (2, 0),
644 _ => (1, 0),
645 }
646 }
647
648 fn serialize_padding(buf: &mut [u8], length: usize) {
649 assert!(length <= buf.len());
650 assert!(length <= (core::u8::MAX as usize) + 2);
651
652 #[allow(clippy::comparison_chain)]
653 if length == 1 {
654 buf[0] = 0
656 } else if length > 1 {
657 buf[0] = 1;
659 buf[1] = (length - 2) as u8;
660 #[allow(clippy::needless_range_loop)]
661 for i in 2..length {
662 buf[i] = 0
663 }
664 }
665 }
666}
667
668#[derive(Debug)]
684pub struct FragmentData<'a> {
685 bytes: &'a [u8],
686}
687
688impl<'a> FragmentData<'a> {
689 pub fn fragment_offset(&self) -> FragmentOffset {
691 debug_assert!(self.bytes.len() == 6);
692 FragmentOffset::new_with_msb(U16::from_bytes([self.bytes[0], self.bytes[1]]).get())
693 }
694
695 pub fn m_flag(&self) -> bool {
697 debug_assert!(self.bytes.len() == 6);
698 (self.bytes[1] & 0x1) == 0x01
699 }
700
701 pub fn identification(&self) -> u32 {
703 debug_assert!(self.bytes.len() == 6);
704 NetworkEndian::read_u32(&self.bytes[2..6])
705 }
706}
707
708#[derive(Debug)]
714pub struct DestinationOptionsData<'a> {
715 options: Records<&'a [u8], DestinationOptionsImpl>,
716}
717
718impl<'a> DestinationOptionsData<'a> {
719 fn new(options: Records<&'a [u8], DestinationOptionsImpl>) -> DestinationOptionsData<'a> {
721 DestinationOptionsData { options }
722 }
723
724 pub fn iter(&'a self) -> impl Iterator<Item = DestinationOption<'a>> {
727 self.options.iter()
728 }
729}
730
731pub type DestinationOption<'a> = ExtensionHeaderOption<DestinationOptionData<'a>>;
733
734pub(super) type DestinationOptionsImpl = ExtensionHeaderOptionImpl<DestinationOptionDataImpl>;
737
738#[allow(missing_docs)]
740#[derive(Debug)]
741pub enum DestinationOptionData<'a> {
742 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
743}
744
745#[derive(Debug)]
747pub(super) struct DestinationOptionDataImpl;
748
749impl ExtensionHeaderOptionDataImplLayout for DestinationOptionDataImpl {
750 type Context = ();
751}
752
753impl ExtensionHeaderOptionDataImpl for DestinationOptionDataImpl {
754 type OptionData<'a> = DestinationOptionData<'a>;
755
756 fn parse_option<'a>(
757 kind: u8,
758 data: &'a [u8],
759 _context: &mut Self::Context,
760 allow_unrecognized: bool,
761 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
762 if allow_unrecognized {
763 ExtensionHeaderOptionDataParseResult::Ok(DestinationOptionData::Unrecognized {
764 kind,
765 len: data.len() as u8,
766 data,
767 })
768 } else {
769 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
770 }
771 }
772}
773
774#[derive(Debug, Clone)]
780pub(super) struct ExtensionHeaderOptionContext<C: Sized + Clone> {
781 options_parsed: usize,
783
784 bytes_parsed: usize,
786
787 specific_context: C,
789}
790
791impl<C: Sized + Clone + Default> ExtensionHeaderOptionContext<C> {
792 fn new() -> Self {
793 ExtensionHeaderOptionContext {
794 options_parsed: 0,
795 bytes_parsed: 0,
796 specific_context: C::default(),
797 }
798 }
799}
800
801impl<C: Sized + Clone> RecordsContext for ExtensionHeaderOptionContext<C> {
802 type Counter = ();
803
804 fn counter_mut(&mut self) -> &mut () {
805 get_empty_tuple_mut_ref()
806 }
807}
808
809pub(super) trait ExtensionHeaderOptionDataImplLayout {
811 type Context: RecordsContext;
814}
815
816#[derive(PartialEq, Eq, Debug)]
818pub enum ExtensionHeaderOptionDataParseResult<D> {
819 Ok(D),
821
822 ErrorAt(u32),
828
829 UnrecognizedKind,
831}
832
833pub(super) trait ExtensionHeaderOptionDataImpl: ExtensionHeaderOptionDataImplLayout {
835 type OptionData<'a>: Sized;
841
842 fn parse_option<'a>(
853 kind: u8,
854 data: &'a [u8],
855 context: &mut Self::Context,
856 allow_unrecognized: bool,
857 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>>;
858}
859
860#[derive(Debug)]
867pub(super) struct ExtensionHeaderOptionImpl<O>(PhantomData<O>);
868
869impl<O> ExtensionHeaderOptionImpl<O> {
870 const PAD1: u8 = 0;
871 const PADN: u8 = 1;
872}
873
874impl<O> RecordsImplLayout for ExtensionHeaderOptionImpl<O>
875where
876 O: ExtensionHeaderOptionDataImplLayout,
877{
878 type Error = ExtensionHeaderOptionParsingError;
879 type Context = ExtensionHeaderOptionContext<O::Context>;
880}
881
882impl<O> RecordsImpl for ExtensionHeaderOptionImpl<O>
883where
884 O: ExtensionHeaderOptionDataImpl,
885{
886 type Record<'a> = ExtensionHeaderOption<O::OptionData<'a>>;
887
888 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
889 data: &mut BV,
890 context: &mut Self::Context,
891 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
892 let kind = match data.take_byte_front() {
894 None => return Ok(ParsedRecord::Done),
895 Some(k) => k,
896 };
897
898 let action =
902 ExtensionHeaderOptionAction::try_from((kind >> 6) & 0x3).expect("Unexpected error");
903 let mutable = ((kind >> 5) & 0x1) == 0x1;
904 let kind = kind & 0x1F;
905
906 if kind == Self::PAD1 {
908 context.options_parsed += 1;
910 context.bytes_parsed += 1;
911
912 return Ok(ParsedRecord::Skipped);
913 }
914
915 let len =
916 data.take_byte_front().ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
917
918 let data = data
919 .take_front(len as usize)
920 .ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
921
922 if kind == Self::PADN {
924 context.options_parsed += 1;
926 context.bytes_parsed += 2 + (len as usize);
927
928 return Ok(ParsedRecord::Skipped);
929 }
930
931 match O::parse_option(
933 kind,
934 data,
935 &mut context.specific_context,
936 action == ExtensionHeaderOptionAction::SkipAndContinue,
937 ) {
938 ExtensionHeaderOptionDataParseResult::Ok(o) => {
939 context.options_parsed += 1;
941 context.bytes_parsed += 2 + (len as usize);
942
943 Ok(ParsedRecord::Parsed(ExtensionHeaderOption { action, mutable, data: o }))
944 }
945 ExtensionHeaderOptionDataParseResult::ErrorAt(offset) => {
946 Err(ExtensionHeaderOptionParsingError::ErroneousOptionField {
951 pointer: u32::try_from(context.bytes_parsed + offset as usize).unwrap(),
952 })
953 }
954 ExtensionHeaderOptionDataParseResult::UnrecognizedKind => {
955 match action {
957 ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
964 "Should never end up here since action was set to skip and continue"
965 ),
966 _ => Err(ExtensionHeaderOptionParsingError::UnrecognizedOption {
977 pointer: u32::try_from(context.bytes_parsed).unwrap(),
978 action,
979 }),
980 }
981 }
982 }
983 }
984}
985
986#[allow(missing_docs)]
988#[derive(Debug, PartialEq, Eq)]
989pub(crate) enum ExtensionHeaderOptionParsingError {
990 ErroneousOptionField { pointer: u32 },
991 UnrecognizedOption { pointer: u32, action: ExtensionHeaderOptionAction },
992 BufferExhausted,
993}
994
995impl From<Never> for ExtensionHeaderOptionParsingError {
996 fn from(err: Never) -> ExtensionHeaderOptionParsingError {
997 match err {}
998 }
999}
1000
1001#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1007pub enum ExtensionHeaderOptionAction {
1008 SkipAndContinue,
1011
1012 DiscardPacket,
1015
1016 DiscardPacketSendIcmp,
1022
1023 DiscardPacketSendIcmpNoMulticast,
1029}
1030
1031impl TryFrom<u8> for ExtensionHeaderOptionAction {
1032 type Error = ();
1033
1034 fn try_from(value: u8) -> Result<Self, ()> {
1035 match value {
1036 0 => Ok(ExtensionHeaderOptionAction::SkipAndContinue),
1037 1 => Ok(ExtensionHeaderOptionAction::DiscardPacket),
1038 2 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmp),
1039 3 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast),
1040 _ => Err(()),
1041 }
1042 }
1043}
1044
1045impl From<ExtensionHeaderOptionAction> for u8 {
1046 fn from(a: ExtensionHeaderOptionAction) -> u8 {
1047 match a {
1048 ExtensionHeaderOptionAction::SkipAndContinue => 0,
1049 ExtensionHeaderOptionAction::DiscardPacket => 1,
1050 ExtensionHeaderOptionAction::DiscardPacketSendIcmp => 2,
1051 ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => 3,
1052 }
1053 }
1054}
1055
1056#[derive(PartialEq, Eq, Debug, Clone)]
1062pub struct ExtensionHeaderOption<O> {
1063 pub action: ExtensionHeaderOptionAction,
1065
1066 pub mutable: bool,
1072
1073 pub data: O,
1075}
1076
1077pub(super) fn is_valid_next_header(next_header: u8, for_fixed_header: bool) -> bool {
1091 match Ipv6ExtHdrType::from(next_header) {
1095 Ipv6ExtHdrType::HopByHopOptions => for_fixed_header,
1098
1099 Ipv6ExtHdrType::Other(next_header) => is_valid_next_header_upper_layer(next_header),
1102
1103 _ => true,
1105 }
1106}
1107
1108pub(super) fn is_valid_next_header_upper_layer(next_header: u8) -> bool {
1113 match Ipv6Proto::from(next_header) {
1114 Ipv6Proto::Proto(IpProto::Tcp)
1115 | Ipv6Proto::Proto(IpProto::Udp)
1116 | Ipv6Proto::Icmpv6
1117 | Ipv6Proto::NoNextHeader => true,
1118 Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => false,
1119 }
1120}
1121
1122fn ext_hdr_opt_err_to_ext_hdr_err(
1131 offset: u32,
1132 header_len: usize,
1133 err: ExtensionHeaderOptionParsingError,
1134) -> Ipv6ExtensionHeaderParsingError {
1135 match err {
1136 ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer } => {
1137 Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1138 pointer: offset + pointer,
1139 must_send_icmp: false,
1144 header_len,
1145 }
1146 }
1147 ExtensionHeaderOptionParsingError::UnrecognizedOption { pointer, action } => {
1148 Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1149 pointer: offset + pointer,
1150 must_send_icmp: true,
1151 header_len,
1152 action,
1153 }
1154 }
1155 ExtensionHeaderOptionParsingError::BufferExhausted => {
1156 Ipv6ExtensionHeaderParsingError::BufferExhausted
1157 }
1158 }
1159}
1160
1161fn get_empty_tuple_mut_ref<'a>() -> &'a mut () {
1162 let bytes: &mut [u8] = &mut [];
1164 zerocopy::Ref::into_mut(zerocopy::Ref::<_, ()>::from_bytes(bytes).unwrap())
1165}
1166
1167#[cfg(test)]
1168mod tests {
1169 use packet::records::{AlignedRecordSequenceBuilder, RecordBuilder};
1170
1171 use crate::ip::Ipv4Proto;
1172
1173 use super::*;
1174
1175 #[test]
1176 fn test_is_valid_next_header_upper_layer() {
1177 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1179 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1180
1181 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1183 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1184
1185 assert!(!is_valid_next_header(255, true));
1188 assert!(!is_valid_next_header(255, false));
1189 }
1190
1191 #[test]
1192 fn test_is_valid_next_header() {
1193 assert!(is_valid_next_header(Ipv6ExtHdrType::HopByHopOptions.into(), true));
1196 assert!(!is_valid_next_header(Ipv6ExtHdrType::HopByHopOptions.into(), false));
1197
1198 assert!(is_valid_next_header(Ipv6ExtHdrType::Routing.into(), true));
1201 assert!(is_valid_next_header(Ipv6ExtHdrType::Routing.into(), false));
1202
1203 assert!(is_valid_next_header(IpProto::Tcp.into(), true));
1205 assert!(is_valid_next_header(IpProto::Tcp.into(), false));
1206
1207 assert!(!is_valid_next_header(Ipv4Proto::Icmp.into(), true));
1209 assert!(!is_valid_next_header(Ipv4Proto::Icmp.into(), false));
1210
1211 assert!(!is_valid_next_header(255, true));
1214 assert!(!is_valid_next_header(255, false));
1215 }
1216
1217 #[test]
1218 fn test_hop_by_hop_options() {
1219 let buffer = [0; 10];
1221 let mut context = ExtensionHeaderOptionContext::new();
1222 let options =
1223 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1224 .unwrap();
1225 assert_eq!(options.iter().count(), 0);
1226 assert_eq!(context.bytes_parsed, 10);
1227 assert_eq!(context.options_parsed, 10);
1228
1229 #[rustfmt::skip]
1231 let buffer = [
1232 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1236 let mut context = ExtensionHeaderOptionContext::new();
1237 let options =
1238 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1239 .unwrap();
1240 assert_eq!(options.iter().count(), 0);
1241 assert_eq!(context.bytes_parsed, 13);
1242 assert_eq!(context.options_parsed, 3);
1243
1244 #[rustfmt::skip]
1247 let buffer = [
1248 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1252 let mut context = ExtensionHeaderOptionContext::new();
1253 let options =
1254 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1255 .unwrap();
1256 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1257 assert_eq!(options.len(), 1);
1258 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1259 assert_eq!(context.bytes_parsed, 12);
1260 assert_eq!(context.options_parsed, 3);
1261 }
1262
1263 #[test]
1264 fn test_hop_by_hop_options_err() {
1265 #[rustfmt::skip]
1267 let buffer = [
1268 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1272 let mut context = ExtensionHeaderOptionContext::new();
1273 assert_eq!(
1274 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1275 .expect_err("Parsed successfully when we were short 2 bytes"),
1276 ExtensionHeaderOptionParsingError::BufferExhausted
1277 );
1278 assert_eq!(context.bytes_parsed, 3);
1279 assert_eq!(context.options_parsed, 2);
1280
1281 #[rustfmt::skip]
1283 let buffer = [
1284 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1288 let mut context = ExtensionHeaderOptionContext::new();
1289 assert_eq!(
1290 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1291 .expect_err("Parsed successfully when we had an unrecognized option type"),
1292 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1293 pointer: 3,
1294 action: ExtensionHeaderOptionAction::DiscardPacket,
1295 }
1296 );
1297 assert_eq!(context.bytes_parsed, 3);
1298 assert_eq!(context.options_parsed, 1);
1299
1300 #[rustfmt::skip]
1303 let buffer = [
1304 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1309 let mut context = ExtensionHeaderOptionContext::new();
1310 assert_eq!(
1311 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1312 .expect_err("Parsed successfully when we had an unrecognized option type"),
1313 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1314 pointer: 3,
1315 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1316 }
1317 );
1318 assert_eq!(context.bytes_parsed, 3);
1319 assert_eq!(context.options_parsed, 1);
1320
1321 #[rustfmt::skip]
1324 let buffer = [
1325 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1330 let mut context = ExtensionHeaderOptionContext::new();
1331 assert_eq!(
1332 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1333 .expect_err("Parsed successfully when we had an unrecognized option type"),
1334 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1335 pointer: 3,
1336 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1337 }
1338 );
1339 assert_eq!(context.bytes_parsed, 3);
1340 assert_eq!(context.options_parsed, 1);
1341 }
1342
1343 #[test]
1344 fn test_destination_options() {
1345 let buffer = [0; 10];
1347 let mut context = ExtensionHeaderOptionContext::new();
1348 let options =
1349 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1350 .unwrap();
1351 assert_eq!(options.iter().count(), 0);
1352 assert_eq!(context.bytes_parsed, 10);
1353 assert_eq!(context.options_parsed, 10);
1354
1355 #[rustfmt::skip]
1357 let buffer = [
1358 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1362 let mut context = ExtensionHeaderOptionContext::new();
1363 let options =
1364 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1365 .unwrap();
1366 assert_eq!(options.iter().count(), 0);
1367 assert_eq!(context.bytes_parsed, 13);
1368 assert_eq!(context.options_parsed, 3);
1369
1370 #[rustfmt::skip]
1373 let buffer = [
1374 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1378 let mut context = ExtensionHeaderOptionContext::new();
1379 let options =
1380 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1381 .unwrap();
1382 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1383 assert_eq!(options.len(), 1);
1384 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1385 assert_eq!(context.bytes_parsed, 12);
1386 assert_eq!(context.options_parsed, 3);
1387 }
1388
1389 #[test]
1390 fn test_destination_options_err() {
1391 #[rustfmt::skip]
1393 let buffer = [
1394 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1398 let mut context = ExtensionHeaderOptionContext::new();
1399 assert_eq!(
1400 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1401 .expect_err("Parsed successfully when we were short 2 bytes"),
1402 ExtensionHeaderOptionParsingError::BufferExhausted
1403 );
1404 assert_eq!(context.bytes_parsed, 3);
1405 assert_eq!(context.options_parsed, 2);
1406
1407 #[rustfmt::skip]
1409 let buffer = [
1410 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1414 let mut context = ExtensionHeaderOptionContext::new();
1415 assert_eq!(
1416 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1417 .expect_err("Parsed successfully when we had an unrecognized option type"),
1418 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1419 pointer: 3,
1420 action: ExtensionHeaderOptionAction::DiscardPacket,
1421 }
1422 );
1423 assert_eq!(context.bytes_parsed, 3);
1424 assert_eq!(context.options_parsed, 1);
1425
1426 #[rustfmt::skip]
1429 let buffer = [
1430 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1435 let mut context = ExtensionHeaderOptionContext::new();
1436 assert_eq!(
1437 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1438 .expect_err("Parsed successfully when we had an unrecognized option type"),
1439 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1440 pointer: 3,
1441 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1442 }
1443 );
1444 assert_eq!(context.bytes_parsed, 3);
1445 assert_eq!(context.options_parsed, 1);
1446
1447 #[rustfmt::skip]
1450 let buffer = [
1451 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1456 let mut context = ExtensionHeaderOptionContext::new();
1457 assert_eq!(
1458 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1459 .expect_err("Parsed successfully when we had an unrecognized option type"),
1460 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1461 pointer: 3,
1462 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1463 }
1464 );
1465 assert_eq!(context.bytes_parsed, 3);
1466 assert_eq!(context.options_parsed, 1);
1467 }
1468
1469 #[test]
1470 fn test_hop_by_hop_options_ext_hdr() {
1471 let context =
1474 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1475 #[rustfmt::skip]
1476 let buffer = [
1477 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1482 let ext_hdrs =
1483 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1484 .unwrap();
1485 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1486 assert_eq!(ext_hdrs.len(), 1);
1487 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1488 if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1489 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1491 assert_eq!(options.len(), 1);
1492 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1493 } else {
1494 panic!("Should have matched HopByHopOptions {:?}", ext_hdrs[0].data());
1495 }
1496 }
1497
1498 #[test]
1499 fn test_hop_by_hop_options_ext_hdr_err() {
1500 let context =
1504 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1505 #[rustfmt::skip]
1506 let buffer = [
1507 255, 0, 1, 4, 0, 0, 0, 0, ];
1511 let error =
1512 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1513 .expect_err("Parsed successfully when the next header was invalid");
1514 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
1515 pointer,
1516 must_send_icmp,
1517 header_len,
1518 } = error
1519 {
1520 assert_eq!(pointer, 0);
1521 assert!(!must_send_icmp);
1522 assert_eq!(header_len, 0);
1523 } else {
1524 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1525 }
1526
1527 let context =
1529 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1530 #[rustfmt::skip]
1531 let buffer = [
1532 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1537 let error =
1538 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1539 .expect_err("Parsed successfully with an unrecognized option type");
1540 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1541 pointer,
1542 must_send_icmp,
1543 header_len,
1544 action,
1545 } = error
1546 {
1547 assert_eq!(pointer, 8);
1548 assert!(must_send_icmp);
1549 assert_eq!(header_len, 0);
1550 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1551 } else {
1552 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1553 }
1554
1555 let context =
1557 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1558 #[rustfmt::skip]
1559 let buffer = [
1560 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1565 let error =
1566 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1567 .expect_err("Parsed successfully with an unrecognized option type");
1568 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1569 pointer,
1570 must_send_icmp,
1571 header_len,
1572 action,
1573 } = error
1574 {
1575 assert_eq!(pointer, 8);
1576 assert!(must_send_icmp);
1577 assert_eq!(header_len, 0);
1578 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1579 } else {
1580 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1581 }
1582
1583 let context =
1585 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1586 #[rustfmt::skip]
1587 let buffer = [
1588 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1594 let error =
1595 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1596 .expect_err("Parsed successfully with an unrecognized option type");
1597 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1598 pointer,
1599 must_send_icmp,
1600 header_len,
1601 action,
1602 } = error
1603 {
1604 assert_eq!(pointer, 8);
1605 assert!(must_send_icmp);
1606 assert_eq!(header_len, 0);
1607 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1608 } else {
1609 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1610 }
1611
1612 let context =
1614 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1615 #[rustfmt::skip]
1616 let buffer = [
1617 IpProto::Tcp.into(), 0, 5, 3, 0, 0, 0, 0, ];
1622 let error =
1623 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1624 .expect_err(
1625 "Should fail to parse the header because one of the option is malformed",
1626 );
1627 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1628 pointer, header_len, ..
1629 } = error
1630 {
1631 assert_eq!(pointer, 3);
1632 assert_eq!(header_len, 0);
1633 } else {
1634 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1635 }
1636 }
1637
1638 #[test]
1639 fn test_routing_ext_hdr() {
1640 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1642 #[rustfmt::skip]
1643 let buffer = [
1644 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,
1651 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1652
1653 ];
1654 let ext_hdrs =
1655 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1656 .unwrap();
1657 assert_eq!(ext_hdrs.iter().count(), 0);
1658 }
1659
1660 #[test]
1661 fn test_routing_ext_hdr_err() {
1662 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1666 #[rustfmt::skip]
1667 let buffer = [
1668 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,
1675 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1676 ];
1677 let error =
1678 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1679 .expect_err("Parsed successfully when the routing type was set to 0");
1680 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1681 pointer,
1682 must_send_icmp,
1683 header_len,
1684 } = error
1685 {
1686 assert_eq!(pointer, 2);
1687 assert!(must_send_icmp);
1688 assert_eq!(header_len, 0);
1689 } else {
1690 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1691 }
1692
1693 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1695 #[rustfmt::skip]
1696 let buffer = [
1697 255, 4, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1704 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1705
1706 ];
1707 let error =
1708 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1709 .expect_err("Parsed successfully when the next header was invalid");
1710 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
1711 pointer,
1712 must_send_icmp,
1713 header_len,
1714 } = error
1715 {
1716 assert_eq!(pointer, 0);
1717 assert!(!must_send_icmp);
1718 assert_eq!(header_len, 0);
1719 } else {
1720 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1721 }
1722
1723 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1725 #[rustfmt::skip]
1726 let buffer = [
1727 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,
1734 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1735
1736 ];
1737 let error =
1738 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1739 .expect_err("Parsed successfully with an unrecognized routing type");
1740 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1741 pointer,
1742 must_send_icmp,
1743 header_len,
1744 } = error
1745 {
1746 assert_eq!(pointer, 2);
1748 assert!(must_send_icmp);
1749 assert_eq!(header_len, 0);
1750 } else {
1751 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1752 }
1753 }
1754
1755 #[test]
1756 fn test_fragment_ext_hdr() {
1757 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1759 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1760 let identification: u32 = 3266246449;
1761 #[rustfmt::skip]
1762 let buffer = [
1763 IpProto::Tcp.into(), 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1769 ((identification >> 16) & 0xFF) as u8,
1770 ((identification >> 8) & 0xFF) as u8,
1771 (identification & 0xFF) as u8,
1772 ];
1773 let ext_hdrs =
1774 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1775 .unwrap();
1776 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1777 assert_eq!(ext_hdrs.len(), 1);
1778 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1779
1780 if let Ipv6ExtensionHeaderData::Fragment { fragment_data } = ext_hdrs[0].data() {
1781 assert_eq!(fragment_data.fragment_offset().into_raw(), 5063);
1782 assert_eq!(fragment_data.m_flag(), true);
1783 assert_eq!(fragment_data.identification(), 3266246449);
1784 } else {
1785 panic!("Should have matched Fragment: {:?}", ext_hdrs[0].data());
1786 }
1787 }
1788
1789 #[test]
1790 fn test_fragment_ext_hdr_err() {
1791 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1795 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1796 let identification: u32 = 3266246449;
1797 #[rustfmt::skip]
1798 let buffer = [
1799 255, 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1805 ((identification >> 16) & 0xFF) as u8,
1806 ((identification >> 8) & 0xFF) as u8,
1807 (identification & 0xFF) as u8,
1808 ];
1809 let error =
1810 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1811 .expect_err("Parsed successfully when the next header was invalid");
1812 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
1813 pointer,
1814 must_send_icmp,
1815 header_len,
1816 } = error
1817 {
1818 assert_eq!(pointer, 0);
1819 assert!(!must_send_icmp);
1820 assert_eq!(header_len, 0);
1821 } else {
1822 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1823 }
1824 }
1825
1826 #[test]
1827 fn test_no_next_header_ext_hdr() {
1828 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6Proto::NoNextHeader.into());
1830 #[rustfmt::skip]
1831 let buffer = [0, 0, 0, 0,];
1832 let ext_hdrs =
1833 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1834 .unwrap();
1835 assert_eq!(ext_hdrs.iter().count(), 0);
1836 }
1837
1838 #[test]
1839 fn test_destination_options_ext_hdr() {
1840 let context =
1843 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1844 #[rustfmt::skip]
1845 let buffer = [
1846 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1851 let ext_hdrs =
1852 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1853 .unwrap();
1854 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1855 assert_eq!(ext_hdrs.len(), 1);
1856 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1857 if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[0].data() {
1858 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1860 assert_eq!(options.len(), 1);
1861 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1862 } else {
1863 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[0].data());
1864 }
1865 }
1866
1867 #[test]
1868 fn test_destination_options_ext_hdr_err() {
1869 let context =
1871 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1872
1873 #[rustfmt::skip]
1875 let buffer = [
1876 255, 0, 1, 4, 0, 0, 0, 0, ];
1880 let error =
1881 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1882 .expect_err("Parsed successfully when the next header was invalid");
1883 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
1884 pointer,
1885 must_send_icmp,
1886 header_len,
1887 } = error
1888 {
1889 assert_eq!(pointer, 0);
1890 assert!(!must_send_icmp);
1891 assert_eq!(header_len, 0);
1892 } else {
1893 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1894 }
1895
1896 let context =
1898 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1899 #[rustfmt::skip]
1900 let buffer = [
1901 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1906 let error =
1907 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1908 .expect_err("Parsed successfully with an unrecognized option type");
1909 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1910 pointer,
1911 must_send_icmp,
1912 header_len,
1913 action,
1914 } = error
1915 {
1916 assert_eq!(pointer, 8);
1917 assert!(must_send_icmp);
1918 assert_eq!(header_len, 0);
1919 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1920 } else {
1921 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1922 }
1923
1924 let context =
1926 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1927 #[rustfmt::skip]
1928 let buffer = [
1929 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1934 let error =
1935 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1936 .expect_err("Parsed successfully with an unrecognized option type");
1937 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1938 pointer,
1939 must_send_icmp,
1940 header_len,
1941 action,
1942 } = error
1943 {
1944 assert_eq!(pointer, 8);
1945 assert!(must_send_icmp);
1946 assert_eq!(header_len, 0);
1947 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1948 } else {
1949 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1950 }
1951
1952 let context =
1954 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1955 #[rustfmt::skip]
1956 let buffer = [
1957 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1963 let error =
1964 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1965 .expect_err("Parsed successfully with an unrecognized option type");
1966 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1967 pointer,
1968 must_send_icmp,
1969 header_len,
1970 action,
1971 } = error
1972 {
1973 assert_eq!(pointer, 8);
1974 assert!(must_send_icmp);
1975 assert_eq!(header_len, 0);
1976 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1977 } else {
1978 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1979 }
1980 }
1981
1982 #[test]
1983 fn test_multiple_ext_hdrs() {
1984 let context =
1986 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1987 #[rustfmt::skip]
1988 let buffer = [
1989 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,
2004 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2005
2006 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
2014 let ext_hdrs =
2015 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2016 .unwrap();
2017
2018 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
2019 assert_eq!(ext_hdrs.len(), 2);
2020
2021 assert_eq!(ext_hdrs[0].next_header, Ipv6ExtHdrType::Routing.into());
2023 if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
2024 assert_eq!(options.iter().count(), 0);
2026 } else {
2027 panic!("Should have matched HopByHopOptions: {:?}", ext_hdrs[0].data());
2028 }
2029
2030 assert_eq!(ext_hdrs[1].next_header, IpProto::Tcp.into());
2035 if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[1].data() {
2036 let options: Vec<DestinationOption<'_>> = options.iter().collect();
2038 assert_eq!(options.len(), 1);
2039 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
2040 } else {
2041 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[2].data());
2042 }
2043 }
2044
2045 #[test]
2046 fn test_multiple_ext_hdrs_errs() {
2047 let context =
2051 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2052 #[rustfmt::skip]
2053 let buffer = [
2054 Ipv6ExtHdrType::Routing.into(), 0, 0, 1, 0, 1, 1, 0, 255, 4, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2069 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2070
2071 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 the next header was invalid");
2082 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
2083 pointer,
2084 must_send_icmp,
2085 header_len,
2086 } = error
2087 {
2088 assert_eq!(pointer, 8);
2089 assert!(!must_send_icmp);
2090 assert_eq!(header_len, 8);
2091 } else {
2092 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2093 }
2094
2095 let context =
2097 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2098 #[rustfmt::skip]
2099 let buffer = [
2100 Ipv6ExtHdrType::HopByHopOptions.into(), 4, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2108 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2109
2110 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, ];
2125 let error =
2126 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2127 .expect_err("Parsed successfully when a hop by hop extension header was not the fist extension header");
2128 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
2129 pointer,
2130 must_send_icmp,
2131 header_len,
2132 } = error
2133 {
2134 assert_eq!(pointer, 0);
2135 assert!(!must_send_icmp);
2136 assert_eq!(header_len, 0);
2137 } else {
2138 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2139 }
2140
2141 let context =
2144 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2145 #[rustfmt::skip]
2146 let buffer = [
2147 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, ];
2162 let error =
2163 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2164 .expect_err("Parsed successfully with an unrecognized destination option type");
2165 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
2166 pointer,
2167 must_send_icmp,
2168 header_len,
2169 action,
2170 } = error
2171 {
2172 assert_eq!(pointer, 16);
2173 assert!(must_send_icmp);
2174 assert_eq!(header_len, 8);
2175 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
2176 } else {
2177 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2178 }
2179 }
2180
2181 #[test]
2182 fn test_serialize_hbh_router_alert() {
2183 let mut buffer = [0u8; 4];
2184 let option = HopByHopOption {
2185 action: ExtensionHeaderOptionAction::SkipAndContinue,
2186 mutable: false,
2187 data: HopByHopOptionData::RouterAlert { data: 0 },
2188 };
2189 <HopByHopOption<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
2190 assert_eq!(&buffer[..], &[5, 2, 0, 0]);
2191 }
2192
2193 #[test]
2194 fn test_parse_hbh_router_alert() {
2195 let context = ExtensionHeaderOptionContext::new();
2197 let buffer = [5, 2, 0, 0];
2198
2199 let options =
2200 Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context).unwrap();
2201 let rtralrt = options.iter().next().unwrap();
2202 assert!(!rtralrt.mutable);
2203 assert_eq!(rtralrt.action, ExtensionHeaderOptionAction::SkipAndContinue);
2204 assert_eq!(rtralrt.data, HopByHopOptionData::RouterAlert { data: 0 });
2205
2206 let result = <HopByHopOptionDataImpl as ExtensionHeaderOptionDataImpl>::parse_option(
2208 5,
2209 &buffer[1..],
2210 &mut (),
2211 false,
2212 );
2213 assert_eq!(result, ExtensionHeaderOptionDataParseResult::ErrorAt(1));
2214
2215 let context = ExtensionHeaderOptionContext::new();
2216 let buffer = [5, 3, 0, 0, 0];
2217
2218 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2219 .expect_err(
2220 "Parsing a malformed option with recognized kind but with wrong data should fail",
2221 );
2222 assert_eq!(error, ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer: 1 });
2223 }
2224
2225 fn trivial_hbh_options(lengths: &[Option<usize>]) -> Vec<HopByHopOption<'static>> {
2232 static ZEROES: [u8; 16] = [0u8; 16];
2233 lengths
2234 .iter()
2235 .map(|l| HopByHopOption {
2236 mutable: false,
2237 action: ExtensionHeaderOptionAction::SkipAndContinue,
2238 data: match l {
2239 Some(l) => HopByHopOptionData::Unrecognized {
2240 kind: 1,
2241 len: (*l - 2) as u8,
2242 data: &ZEROES[0..*l - 2],
2243 },
2244 None => HopByHopOptionData::RouterAlert { data: 0 },
2245 },
2246 })
2247 .collect()
2248 }
2249
2250 #[test]
2251 fn test_aligned_records_serializer() {
2252 for i in 2..12 {
2254 let options = trivial_hbh_options(&[Some(i), None]);
2255 let ser = AlignedRecordSequenceBuilder::<
2256 ExtensionHeaderOption<HopByHopOptionData<'_>>,
2257 _,
2258 >::new(2, options.iter());
2259 let mut buf = [0u8; 16];
2260 ser.serialize_into(&mut buf[0..16]);
2261 let base = (i + 1) & !1;
2262 assert_eq!(&buf[base..base + 4], &[5, 2, 0, 0]);
2264 }
2265 }
2266}