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 { pointer: u32, must_send_icmp: bool },
75 UnrecognizedNextHeader { pointer: u32, must_send_icmp: bool },
76 UnrecognizedOption { pointer: u32, must_send_icmp: bool, action: ExtensionHeaderOptionAction },
77 BufferExhausted,
78 MalformedData,
79}
80
81impl From<Never> for Ipv6ExtensionHeaderParsingError {
82 fn from(err: Never) -> Ipv6ExtensionHeaderParsingError {
83 match err {}
84 }
85}
86
87#[derive(Debug, Clone)]
89pub(super) struct Ipv6ExtensionHeaderParsingContext {
90 pub(super) next_header: u8,
94
95 iter: bool,
97
98 headers_parsed: usize,
100
101 pub(super) bytes_parsed: usize,
103}
104
105impl Ipv6ExtensionHeaderParsingContext {
106 pub(super) fn new(next_header: u8) -> Ipv6ExtensionHeaderParsingContext {
109 Ipv6ExtensionHeaderParsingContext {
110 iter: false,
111 headers_parsed: 0,
112 next_header,
113 bytes_parsed: 0,
114 }
115 }
116}
117
118impl RecordsContext for Ipv6ExtensionHeaderParsingContext {
119 type Counter = ();
120
121 fn clone_for_iter(&self) -> Self {
122 let mut ret = self.clone();
123 ret.iter = true;
124 ret
125 }
126
127 fn counter_mut(&mut self) -> &mut () {
128 get_empty_tuple_mut_ref()
129 }
130}
131
132#[derive(Debug)]
134pub(super) struct Ipv6ExtensionHeaderImpl;
135
136impl Ipv6ExtensionHeaderImpl {
137 fn valid_next_header(next_header: u8) -> bool {
139 is_valid_next_header(next_header, false)
143 }
144
145 fn get_next_hdr_and_len<'a, BV: BufferView<&'a [u8]>>(
152 data: &mut BV,
153 context: &Ipv6ExtensionHeaderParsingContext,
154 ) -> Result<(u8, u8), Ipv6ExtensionHeaderParsingError> {
155 let next_header =
156 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
157
158 if !Self::valid_next_header(next_header) {
163 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
164 pointer: context.bytes_parsed as u32,
165 must_send_icmp: false,
166 });
167 }
168
169 let hdr_ext_len =
170 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
171
172 Ok((next_header, hdr_ext_len))
173 }
174
175 fn parse_hop_by_hop_options<'a, BV: BufferView<&'a [u8]>>(
180 data: &mut BV,
181 context: &mut Ipv6ExtensionHeaderParsingContext,
182 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
183 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
184
185 let expected_len = (hdr_ext_len as usize) * 8 + 6;
191
192 let options = data
193 .take_front(expected_len)
194 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
195
196 let options_context = ExtensionHeaderOptionContext::new();
197 let options = Records::parse_with_context(options, options_context).map_err(|e| {
198 ext_hdr_opt_err_to_ext_hdr_err(u32::try_from(context.bytes_parsed + 2).unwrap(), e)
209 })?;
210 let options = HopByHopOptionsData::new(options);
211
212 context.next_header = next_header;
214 context.headers_parsed += 1;
215 context.bytes_parsed += 2 + expected_len;
216
217 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
218 next_header,
219 data: Ipv6ExtensionHeaderData::HopByHopOptions { options },
220 }))
221 }
222
223 fn parse_routing<'a, BV: BufferView<&'a [u8]>>(
225 data: &mut BV,
226 context: &mut Ipv6ExtensionHeaderParsingContext,
227 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
228 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
231 let routing_data =
232 data.take_front(2).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
233 let segments_left = routing_data[1];
234
235 if segments_left == 0 {
247 let expected_len = (hdr_ext_len as usize) * 8 + 4;
251 let _: &[u8] = data
252 .take_front(expected_len)
253 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
254
255 context.next_header = next_header;
257 context.headers_parsed += 1;
258 context.bytes_parsed += expected_len;
259
260 Ok(ParsedRecord::Skipped)
261 } else {
262 Err(Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
266 pointer: (context.bytes_parsed as u32) + 2,
267 must_send_icmp: true,
268 })
269 }
270 }
271
272 fn parse_fragment<'a, BV: BufferView<&'a [u8]>>(
274 data: &mut BV,
275 context: &mut Ipv6ExtensionHeaderParsingContext,
276 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
277 if data.len() < 8 {
283 return Err(Ipv6ExtensionHeaderParsingError::BufferExhausted);
284 }
285
286 let (next_header, _) = Self::get_next_hdr_and_len(data, context)?;
290
291 context.next_header = next_header;
293 context.headers_parsed += 1;
294 context.bytes_parsed += 8;
295
296 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
297 next_header,
298 data: Ipv6ExtensionHeaderData::Fragment {
299 fragment_data: FragmentData { bytes: data.take_front(6).unwrap() },
300 },
301 }))
302 }
303
304 fn parse_destination_options<'a, BV: BufferView<&'a [u8]>>(
306 data: &mut BV,
307 context: &mut Ipv6ExtensionHeaderParsingContext,
308 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
309 let (next_header, hdr_ext_len) = Self::get_next_hdr_and_len(data, context)?;
310
311 let expected_len = (hdr_ext_len as usize) * 8 + 6;
315
316 let options = data
317 .take_front(expected_len)
318 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
319
320 let options_context = ExtensionHeaderOptionContext::new();
321 let options = Records::parse_with_context(options, options_context).map_err(|e| {
322 ext_hdr_opt_err_to_ext_hdr_err(u32::try_from(context.bytes_parsed + 2).unwrap(), e)
333 })?;
334 let options = DestinationOptionsData::new(options);
335
336 context.next_header = next_header;
338 context.headers_parsed += 1;
339 context.bytes_parsed += 2 + expected_len;
340
341 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader {
342 next_header,
343 data: Ipv6ExtensionHeaderData::DestinationOptions { options },
344 }))
345 }
346}
347
348impl RecordsImplLayout for Ipv6ExtensionHeaderImpl {
349 type Context = Ipv6ExtensionHeaderParsingContext;
350 type Error = Ipv6ExtensionHeaderParsingError;
351}
352
353impl RecordsImpl for Ipv6ExtensionHeaderImpl {
354 type Record<'a> = Ipv6ExtensionHeader<'a>;
355
356 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
357 data: &mut BV,
358 context: &mut Self::Context,
359 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
360 let expected_hdr = context.next_header;
361
362 match Ipv6ExtHdrType::from(expected_hdr) {
363 Ipv6ExtHdrType::HopByHopOptions => Self::parse_hop_by_hop_options(data, context),
364 Ipv6ExtHdrType::Routing => Self::parse_routing(data, context),
365 Ipv6ExtHdrType::Fragment => Self::parse_fragment(data, context),
366 Ipv6ExtHdrType::DestinationOptions => Self::parse_destination_options(data, context),
367 Ipv6ExtHdrType::EncapsulatingSecurityPayload | Ipv6ExtHdrType::Authentication => {
368 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
380 pointer: u32::MAX,
383 must_send_icmp: false,
386 })
387 }
388 Ipv6ExtHdrType::Other(_) => {
389 if is_valid_next_header_upper_layer(expected_hdr) {
390 Ok(ParsedRecord::Done)
393 } else {
394 unreachable!(
402 "Should never try parsing an extension header with an unrecognized type"
403 );
404 }
405 }
406 }
407 }
408}
409
410impl<'a> RecordsRawImpl<'a> for Ipv6ExtensionHeaderImpl {
411 fn parse_raw_with_context<BV: BufferView<&'a [u8]>>(
412 data: &mut BV,
413 context: &mut Self::Context,
414 ) -> Result<bool, Self::Error> {
415 if is_valid_next_header_upper_layer(context.next_header) {
416 Ok(false)
417 } else {
418 let (next, skip) = match Ipv6ExtHdrType::from(context.next_header) {
419 Ipv6ExtHdrType::HopByHopOptions
420 | Ipv6ExtHdrType::Routing
421 | Ipv6ExtHdrType::DestinationOptions
422 | Ipv6ExtHdrType::Other(_) => {
423 data.take_front(2)
429 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
430 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
431 }
432 Ipv6ExtHdrType::Fragment => {
433 (
435 data.take_byte_front()
436 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?,
437 7,
438 )
439 }
440 Ipv6ExtHdrType::EncapsulatingSecurityPayload => {
441 return debug_err!(
445 Err(Ipv6ExtensionHeaderParsingError::MalformedData),
446 "ESP extension header not supported"
447 );
448 }
449 Ipv6ExtHdrType::Authentication => {
450 data.take_front(2)
454 .map(|x| (x[0], (x[1] as usize + 2) * 4 - 2))
455 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
456 }
457 };
458 let _: &[u8] =
459 data.take_front(skip).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
460 context.next_header = next;
461 Ok(true)
462 }
463 }
464}
465
466#[derive(Debug)]
472pub struct HopByHopOptionsData<'a> {
473 options: Records<&'a [u8], HopByHopOptionsImpl>,
474}
475
476impl<'a> HopByHopOptionsData<'a> {
477 fn new(options: Records<&'a [u8], HopByHopOptionsImpl>) -> HopByHopOptionsData<'a> {
479 HopByHopOptionsData { options }
480 }
481
482 pub fn iter(&'a self) -> impl Iterator<Item = HopByHopOption<'a>> {
485 self.options.iter()
486 }
487}
488
489pub type HopByHopOption<'a> = ExtensionHeaderOption<HopByHopOptionData<'a>>;
491
492pub(super) type HopByHopOptionsImpl = ExtensionHeaderOptionImpl<HopByHopOptionDataImpl>;
495
496const HBH_OPTION_KIND_RTRALRT: u8 = 5;
500
501const HBH_OPTION_RTRALRT_LEN: usize = 2;
505
506#[allow(missing_docs)]
508#[derive(Debug, PartialEq, Eq, Clone)]
509pub enum HopByHopOptionData<'a> {
510 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
511 RouterAlert { data: u16 },
512}
513
514#[derive(Debug)]
516pub(super) struct HopByHopOptionDataImpl;
517
518impl ExtensionHeaderOptionDataImplLayout for HopByHopOptionDataImpl {
519 type Context = ();
520}
521
522impl ExtensionHeaderOptionDataImpl for HopByHopOptionDataImpl {
523 type OptionData<'a> = HopByHopOptionData<'a>;
524
525 fn parse_option<'a>(
526 kind: u8,
527 data: &'a [u8],
528 _context: &mut Self::Context,
529 allow_unrecognized: bool,
530 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
531 match kind {
532 HBH_OPTION_KIND_RTRALRT => {
533 if data.len() == HBH_OPTION_RTRALRT_LEN {
534 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::RouterAlert {
535 data: NetworkEndian::read_u16(data),
536 })
537 } else {
538 ExtensionHeaderOptionDataParseResult::ErrorAt(1)
541 }
542 }
543 _ => {
544 if allow_unrecognized {
545 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::Unrecognized {
546 kind,
547 len: data.len() as u8,
548 data,
549 })
550 } else {
551 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
552 }
553 }
554 }
555 }
556}
557
558impl OptionLayout for HopByHopOptionsImpl {
559 type KindLenField = u8;
560 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
561}
562
563impl OptionParseLayout for HopByHopOptionsImpl {
564 type Error = OptionParseErr;
565 const END_OF_OPTIONS: Option<u8> = Some(0);
566 const NOP: Option<u8> = Some(1);
567}
568
569#[doc(hidden)]
575pub enum HopByHopOptionLayout {}
576
577impl OptionLayout for HopByHopOptionLayout {
578 type KindLenField = u8;
579 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
580}
581
582impl<'a> OptionBuilder for HopByHopOption<'a> {
583 type Layout = HopByHopOptionLayout;
584 fn serialized_len(&self) -> usize {
585 match self.data {
586 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_RTRALRT_LEN,
587 HopByHopOptionData::Unrecognized { len, .. } => len as usize,
588 }
589 }
590
591 fn option_kind(&self) -> u8 {
592 let action: u8 = self.action.into();
593 let mutable = self.mutable as u8;
594 let type_number = match self.data {
595 HopByHopOptionData::Unrecognized { kind, .. } => kind,
596 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_KIND_RTRALRT,
597 };
598 (action << 6) | (mutable << 5) | type_number
599 }
600
601 fn serialize_into(&self, mut buffer: &mut [u8]) {
602 match self.data {
603 HopByHopOptionData::Unrecognized { data, .. } => buffer.copy_from_slice(data),
604 HopByHopOptionData::RouterAlert { data } => {
605 (&mut buffer).write_obj_front(&U16::new(data)).unwrap()
608 }
609 }
610 }
611}
612
613impl<'a> AlignedOptionBuilder for HopByHopOption<'a> {
614 fn alignment_requirement(&self) -> (usize, usize) {
615 match self.data {
616 HopByHopOptionData::RouterAlert { .. } => (2, 0),
619 _ => (1, 0),
620 }
621 }
622
623 fn serialize_padding(buf: &mut [u8], length: usize) {
624 assert!(length <= buf.len());
625 assert!(length <= (core::u8::MAX as usize) + 2);
626
627 #[allow(clippy::comparison_chain)]
628 if length == 1 {
629 buf[0] = 0
631 } else if length > 1 {
632 buf[0] = 1;
634 buf[1] = (length - 2) as u8;
635 #[allow(clippy::needless_range_loop)]
636 for i in 2..length {
637 buf[i] = 0
638 }
639 }
640 }
641}
642
643#[derive(Debug)]
659pub struct FragmentData<'a> {
660 bytes: &'a [u8],
661}
662
663impl<'a> FragmentData<'a> {
664 pub fn fragment_offset(&self) -> FragmentOffset {
666 debug_assert!(self.bytes.len() == 6);
667 FragmentOffset::new_with_msb(U16::from_bytes([self.bytes[0], self.bytes[1]]).get())
668 }
669
670 pub fn m_flag(&self) -> bool {
672 debug_assert!(self.bytes.len() == 6);
673 (self.bytes[1] & 0x1) == 0x01
674 }
675
676 pub fn identification(&self) -> u32 {
678 debug_assert!(self.bytes.len() == 6);
679 NetworkEndian::read_u32(&self.bytes[2..6])
680 }
681}
682
683#[derive(Debug)]
689pub struct DestinationOptionsData<'a> {
690 options: Records<&'a [u8], DestinationOptionsImpl>,
691}
692
693impl<'a> DestinationOptionsData<'a> {
694 fn new(options: Records<&'a [u8], DestinationOptionsImpl>) -> DestinationOptionsData<'a> {
696 DestinationOptionsData { options }
697 }
698
699 pub fn iter(&'a self) -> impl Iterator<Item = DestinationOption<'a>> {
702 self.options.iter()
703 }
704}
705
706pub type DestinationOption<'a> = ExtensionHeaderOption<DestinationOptionData<'a>>;
708
709pub(super) type DestinationOptionsImpl = ExtensionHeaderOptionImpl<DestinationOptionDataImpl>;
712
713#[allow(missing_docs)]
715#[derive(Debug)]
716pub enum DestinationOptionData<'a> {
717 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
718}
719
720#[derive(Debug)]
722pub(super) struct DestinationOptionDataImpl;
723
724impl ExtensionHeaderOptionDataImplLayout for DestinationOptionDataImpl {
725 type Context = ();
726}
727
728impl ExtensionHeaderOptionDataImpl for DestinationOptionDataImpl {
729 type OptionData<'a> = DestinationOptionData<'a>;
730
731 fn parse_option<'a>(
732 kind: u8,
733 data: &'a [u8],
734 _context: &mut Self::Context,
735 allow_unrecognized: bool,
736 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
737 if allow_unrecognized {
738 ExtensionHeaderOptionDataParseResult::Ok(DestinationOptionData::Unrecognized {
739 kind,
740 len: data.len() as u8,
741 data,
742 })
743 } else {
744 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
745 }
746 }
747}
748
749#[derive(Debug, Clone)]
755pub(super) struct ExtensionHeaderOptionContext<C: Sized + Clone> {
756 options_parsed: usize,
758
759 bytes_parsed: usize,
761
762 specific_context: C,
764}
765
766impl<C: Sized + Clone + Default> ExtensionHeaderOptionContext<C> {
767 fn new() -> Self {
768 ExtensionHeaderOptionContext {
769 options_parsed: 0,
770 bytes_parsed: 0,
771 specific_context: C::default(),
772 }
773 }
774}
775
776impl<C: Sized + Clone> RecordsContext for ExtensionHeaderOptionContext<C> {
777 type Counter = ();
778
779 fn counter_mut(&mut self) -> &mut () {
780 get_empty_tuple_mut_ref()
781 }
782}
783
784pub(super) trait ExtensionHeaderOptionDataImplLayout {
786 type Context: RecordsContext;
789}
790
791#[derive(PartialEq, Eq, Debug)]
793pub enum ExtensionHeaderOptionDataParseResult<D> {
794 Ok(D),
796
797 ErrorAt(u32),
803
804 UnrecognizedKind,
806}
807
808pub(super) trait ExtensionHeaderOptionDataImpl: ExtensionHeaderOptionDataImplLayout {
810 type OptionData<'a>: Sized;
816
817 fn parse_option<'a>(
828 kind: u8,
829 data: &'a [u8],
830 context: &mut Self::Context,
831 allow_unrecognized: bool,
832 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>>;
833}
834
835#[derive(Debug)]
842pub(super) struct ExtensionHeaderOptionImpl<O>(PhantomData<O>);
843
844impl<O> ExtensionHeaderOptionImpl<O> {
845 const PAD1: u8 = 0;
846 const PADN: u8 = 1;
847}
848
849impl<O> RecordsImplLayout for ExtensionHeaderOptionImpl<O>
850where
851 O: ExtensionHeaderOptionDataImplLayout,
852{
853 type Error = ExtensionHeaderOptionParsingError;
854 type Context = ExtensionHeaderOptionContext<O::Context>;
855}
856
857impl<O> RecordsImpl for ExtensionHeaderOptionImpl<O>
858where
859 O: ExtensionHeaderOptionDataImpl,
860{
861 type Record<'a> = ExtensionHeaderOption<O::OptionData<'a>>;
862
863 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
864 data: &mut BV,
865 context: &mut Self::Context,
866 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
867 let kind = match data.take_byte_front() {
869 None => return Ok(ParsedRecord::Done),
870 Some(k) => k,
871 };
872
873 let action =
877 ExtensionHeaderOptionAction::try_from((kind >> 6) & 0x3).expect("Unexpected error");
878 let mutable = ((kind >> 5) & 0x1) == 0x1;
879 let kind = kind & 0x1F;
880
881 if kind == Self::PAD1 {
883 context.options_parsed += 1;
885 context.bytes_parsed += 1;
886
887 return Ok(ParsedRecord::Skipped);
888 }
889
890 let len =
891 data.take_byte_front().ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
892
893 let data = data
894 .take_front(len as usize)
895 .ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
896
897 if kind == Self::PADN {
899 context.options_parsed += 1;
901 context.bytes_parsed += 2 + (len as usize);
902
903 return Ok(ParsedRecord::Skipped);
904 }
905
906 match O::parse_option(
908 kind,
909 data,
910 &mut context.specific_context,
911 action == ExtensionHeaderOptionAction::SkipAndContinue,
912 ) {
913 ExtensionHeaderOptionDataParseResult::Ok(o) => {
914 context.options_parsed += 1;
916 context.bytes_parsed += 2 + (len as usize);
917
918 Ok(ParsedRecord::Parsed(ExtensionHeaderOption { action, mutable, data: o }))
919 }
920 ExtensionHeaderOptionDataParseResult::ErrorAt(offset) => {
921 Err(ExtensionHeaderOptionParsingError::ErroneousOptionField {
926 pointer: u32::try_from(context.bytes_parsed + offset as usize).unwrap(),
927 })
928 }
929 ExtensionHeaderOptionDataParseResult::UnrecognizedKind => {
930 match action {
932 ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
939 "Should never end up here since action was set to skip and continue"
940 ),
941 _ => Err(ExtensionHeaderOptionParsingError::UnrecognizedOption {
952 pointer: u32::try_from(context.bytes_parsed).unwrap(),
953 action,
954 }),
955 }
956 }
957 }
958 }
959}
960
961#[allow(missing_docs)]
963#[derive(Debug, PartialEq, Eq)]
964pub(crate) enum ExtensionHeaderOptionParsingError {
965 ErroneousOptionField { pointer: u32 },
966 UnrecognizedOption { pointer: u32, action: ExtensionHeaderOptionAction },
967 BufferExhausted,
968}
969
970impl From<Never> for ExtensionHeaderOptionParsingError {
971 fn from(err: Never) -> ExtensionHeaderOptionParsingError {
972 match err {}
973 }
974}
975
976#[derive(Debug, PartialEq, Eq, Clone, Copy)]
982pub enum ExtensionHeaderOptionAction {
983 SkipAndContinue,
986
987 DiscardPacket,
990
991 DiscardPacketSendIcmp,
997
998 DiscardPacketSendIcmpNoMulticast,
1004}
1005
1006impl TryFrom<u8> for ExtensionHeaderOptionAction {
1007 type Error = ();
1008
1009 fn try_from(value: u8) -> Result<Self, ()> {
1010 match value {
1011 0 => Ok(ExtensionHeaderOptionAction::SkipAndContinue),
1012 1 => Ok(ExtensionHeaderOptionAction::DiscardPacket),
1013 2 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmp),
1014 3 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast),
1015 _ => Err(()),
1016 }
1017 }
1018}
1019
1020impl From<ExtensionHeaderOptionAction> for u8 {
1021 fn from(a: ExtensionHeaderOptionAction) -> u8 {
1022 match a {
1023 ExtensionHeaderOptionAction::SkipAndContinue => 0,
1024 ExtensionHeaderOptionAction::DiscardPacket => 1,
1025 ExtensionHeaderOptionAction::DiscardPacketSendIcmp => 2,
1026 ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => 3,
1027 }
1028 }
1029}
1030
1031#[derive(PartialEq, Eq, Debug, Clone)]
1037pub struct ExtensionHeaderOption<O> {
1038 pub action: ExtensionHeaderOptionAction,
1040
1041 pub mutable: bool,
1047
1048 pub data: O,
1050}
1051
1052pub(super) fn is_valid_next_header(next_header: u8, for_fixed_header: bool) -> bool {
1066 match Ipv6ExtHdrType::from(next_header) {
1070 Ipv6ExtHdrType::HopByHopOptions => for_fixed_header,
1073
1074 Ipv6ExtHdrType::Other(next_header) => is_valid_next_header_upper_layer(next_header),
1077
1078 _ => true,
1080 }
1081}
1082
1083pub(super) fn is_valid_next_header_upper_layer(next_header: u8) -> bool {
1088 match Ipv6Proto::from(next_header) {
1089 Ipv6Proto::Proto(IpProto::Tcp)
1090 | Ipv6Proto::Proto(IpProto::Udp)
1091 | Ipv6Proto::Icmpv6
1092 | Ipv6Proto::NoNextHeader => true,
1093 Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => false,
1094 }
1095}
1096
1097fn ext_hdr_opt_err_to_ext_hdr_err(
1103 offset: u32,
1104 err: ExtensionHeaderOptionParsingError,
1105) -> Ipv6ExtensionHeaderParsingError {
1106 match err {
1107 ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer } => {
1108 Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1109 pointer: offset + pointer,
1110 must_send_icmp: false,
1115 }
1116 }
1117 ExtensionHeaderOptionParsingError::UnrecognizedOption { pointer, action } => {
1118 Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1119 pointer: offset + pointer,
1120 must_send_icmp: true,
1121 action,
1122 }
1123 }
1124 ExtensionHeaderOptionParsingError::BufferExhausted => {
1125 Ipv6ExtensionHeaderParsingError::BufferExhausted
1126 }
1127 }
1128}
1129
1130fn get_empty_tuple_mut_ref<'a>() -> &'a mut () {
1131 let bytes: &mut [u8] = &mut [];
1133 zerocopy::Ref::into_mut(zerocopy::Ref::<_, ()>::from_bytes(bytes).unwrap())
1134}
1135
1136#[cfg(test)]
1137mod tests {
1138 use packet::records::{AlignedRecordSequenceBuilder, RecordBuilder};
1139
1140 use crate::ip::Ipv4Proto;
1141
1142 use super::*;
1143
1144 #[test]
1145 fn test_is_valid_next_header_upper_layer() {
1146 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1148 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1149
1150 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1152 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1153
1154 assert!(!is_valid_next_header(255, true));
1157 assert!(!is_valid_next_header(255, false));
1158 }
1159
1160 #[test]
1161 fn test_is_valid_next_header() {
1162 assert!(is_valid_next_header(Ipv6ExtHdrType::HopByHopOptions.into(), true));
1165 assert!(!is_valid_next_header(Ipv6ExtHdrType::HopByHopOptions.into(), false));
1166
1167 assert!(is_valid_next_header(Ipv6ExtHdrType::Routing.into(), true));
1170 assert!(is_valid_next_header(Ipv6ExtHdrType::Routing.into(), false));
1171
1172 assert!(is_valid_next_header(IpProto::Tcp.into(), true));
1174 assert!(is_valid_next_header(IpProto::Tcp.into(), false));
1175
1176 assert!(!is_valid_next_header(Ipv4Proto::Icmp.into(), true));
1178 assert!(!is_valid_next_header(Ipv4Proto::Icmp.into(), false));
1179
1180 assert!(!is_valid_next_header(255, true));
1183 assert!(!is_valid_next_header(255, false));
1184 }
1185
1186 #[test]
1187 fn test_hop_by_hop_options() {
1188 let buffer = [0; 10];
1190 let mut context = ExtensionHeaderOptionContext::new();
1191 let options =
1192 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1193 .unwrap();
1194 assert_eq!(options.iter().count(), 0);
1195 assert_eq!(context.bytes_parsed, 10);
1196 assert_eq!(context.options_parsed, 10);
1197
1198 #[rustfmt::skip]
1200 let buffer = [
1201 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1205 let mut context = ExtensionHeaderOptionContext::new();
1206 let options =
1207 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1208 .unwrap();
1209 assert_eq!(options.iter().count(), 0);
1210 assert_eq!(context.bytes_parsed, 13);
1211 assert_eq!(context.options_parsed, 3);
1212
1213 #[rustfmt::skip]
1216 let buffer = [
1217 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1221 let mut context = ExtensionHeaderOptionContext::new();
1222 let options =
1223 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1224 .unwrap();
1225 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1226 assert_eq!(options.len(), 1);
1227 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1228 assert_eq!(context.bytes_parsed, 12);
1229 assert_eq!(context.options_parsed, 3);
1230 }
1231
1232 #[test]
1233 fn test_hop_by_hop_options_err() {
1234 #[rustfmt::skip]
1236 let buffer = [
1237 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1241 let mut context = ExtensionHeaderOptionContext::new();
1242 assert_eq!(
1243 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1244 .expect_err("Parsed successfully when we were short 2 bytes"),
1245 ExtensionHeaderOptionParsingError::BufferExhausted
1246 );
1247 assert_eq!(context.bytes_parsed, 3);
1248 assert_eq!(context.options_parsed, 2);
1249
1250 #[rustfmt::skip]
1252 let buffer = [
1253 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1257 let mut context = ExtensionHeaderOptionContext::new();
1258 assert_eq!(
1259 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1260 .expect_err("Parsed successfully when we had an unrecognized option type"),
1261 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1262 pointer: 3,
1263 action: ExtensionHeaderOptionAction::DiscardPacket,
1264 }
1265 );
1266 assert_eq!(context.bytes_parsed, 3);
1267 assert_eq!(context.options_parsed, 1);
1268
1269 #[rustfmt::skip]
1272 let buffer = [
1273 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1278 let mut context = ExtensionHeaderOptionContext::new();
1279 assert_eq!(
1280 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1281 .expect_err("Parsed successfully when we had an unrecognized option type"),
1282 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1283 pointer: 3,
1284 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1285 }
1286 );
1287 assert_eq!(context.bytes_parsed, 3);
1288 assert_eq!(context.options_parsed, 1);
1289
1290 #[rustfmt::skip]
1293 let buffer = [
1294 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1299 let mut context = ExtensionHeaderOptionContext::new();
1300 assert_eq!(
1301 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1302 .expect_err("Parsed successfully when we had an unrecognized option type"),
1303 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1304 pointer: 3,
1305 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1306 }
1307 );
1308 assert_eq!(context.bytes_parsed, 3);
1309 assert_eq!(context.options_parsed, 1);
1310 }
1311
1312 #[test]
1313 fn test_destination_options() {
1314 let buffer = [0; 10];
1316 let mut context = ExtensionHeaderOptionContext::new();
1317 let options =
1318 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1319 .unwrap();
1320 assert_eq!(options.iter().count(), 0);
1321 assert_eq!(context.bytes_parsed, 10);
1322 assert_eq!(context.options_parsed, 10);
1323
1324 #[rustfmt::skip]
1326 let buffer = [
1327 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1331 let mut context = ExtensionHeaderOptionContext::new();
1332 let options =
1333 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1334 .unwrap();
1335 assert_eq!(options.iter().count(), 0);
1336 assert_eq!(context.bytes_parsed, 13);
1337 assert_eq!(context.options_parsed, 3);
1338
1339 #[rustfmt::skip]
1342 let buffer = [
1343 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1347 let mut context = ExtensionHeaderOptionContext::new();
1348 let options =
1349 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1350 .unwrap();
1351 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1352 assert_eq!(options.len(), 1);
1353 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1354 assert_eq!(context.bytes_parsed, 12);
1355 assert_eq!(context.options_parsed, 3);
1356 }
1357
1358 #[test]
1359 fn test_destination_options_err() {
1360 #[rustfmt::skip]
1362 let buffer = [
1363 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1367 let mut context = ExtensionHeaderOptionContext::new();
1368 assert_eq!(
1369 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1370 .expect_err("Parsed successfully when we were short 2 bytes"),
1371 ExtensionHeaderOptionParsingError::BufferExhausted
1372 );
1373 assert_eq!(context.bytes_parsed, 3);
1374 assert_eq!(context.options_parsed, 2);
1375
1376 #[rustfmt::skip]
1378 let buffer = [
1379 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1383 let mut context = ExtensionHeaderOptionContext::new();
1384 assert_eq!(
1385 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1386 .expect_err("Parsed successfully when we had an unrecognized option type"),
1387 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1388 pointer: 3,
1389 action: ExtensionHeaderOptionAction::DiscardPacket,
1390 }
1391 );
1392 assert_eq!(context.bytes_parsed, 3);
1393 assert_eq!(context.options_parsed, 1);
1394
1395 #[rustfmt::skip]
1398 let buffer = [
1399 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1404 let mut context = ExtensionHeaderOptionContext::new();
1405 assert_eq!(
1406 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1407 .expect_err("Parsed successfully when we had an unrecognized option type"),
1408 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1409 pointer: 3,
1410 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1411 }
1412 );
1413 assert_eq!(context.bytes_parsed, 3);
1414 assert_eq!(context.options_parsed, 1);
1415
1416 #[rustfmt::skip]
1419 let buffer = [
1420 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1425 let mut context = ExtensionHeaderOptionContext::new();
1426 assert_eq!(
1427 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1428 .expect_err("Parsed successfully when we had an unrecognized option type"),
1429 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1430 pointer: 3,
1431 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1432 }
1433 );
1434 assert_eq!(context.bytes_parsed, 3);
1435 assert_eq!(context.options_parsed, 1);
1436 }
1437
1438 #[test]
1439 fn test_hop_by_hop_options_ext_hdr() {
1440 let context =
1443 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1444 #[rustfmt::skip]
1445 let buffer = [
1446 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1451 let ext_hdrs =
1452 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1453 .unwrap();
1454 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1455 assert_eq!(ext_hdrs.len(), 1);
1456 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1457 if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1458 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1460 assert_eq!(options.len(), 1);
1461 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1462 } else {
1463 panic!("Should have matched HopByHopOptions {:?}", ext_hdrs[0].data());
1464 }
1465 }
1466
1467 #[test]
1468 fn test_hop_by_hop_options_ext_hdr_err() {
1469 let context =
1473 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1474 #[rustfmt::skip]
1475 let buffer = [
1476 255, 0, 1, 4, 0, 0, 0, 0, ];
1480 let error =
1481 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1482 .expect_err("Parsed successfully when the next header was invalid");
1483 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1484 error
1485 {
1486 assert_eq!(pointer, 0);
1487 assert!(!must_send_icmp);
1488 } else {
1489 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1490 }
1491
1492 let context =
1494 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1495 #[rustfmt::skip]
1496 let buffer = [
1497 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1502 let error =
1503 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1504 .expect_err("Parsed successfully with an unrecognized option type");
1505 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1506 pointer,
1507 must_send_icmp,
1508 action,
1509 } = error
1510 {
1511 assert_eq!(pointer, 8);
1512 assert!(must_send_icmp);
1513 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1514 } else {
1515 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1516 }
1517
1518 let context =
1520 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1521 #[rustfmt::skip]
1522 let buffer = [
1523 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1528 let error =
1529 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1530 .expect_err("Parsed successfully with an unrecognized option type");
1531 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1532 pointer,
1533 must_send_icmp,
1534 action,
1535 } = error
1536 {
1537 assert_eq!(pointer, 8);
1538 assert!(must_send_icmp);
1539 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1540 } else {
1541 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1542 }
1543
1544 let context =
1546 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1547 #[rustfmt::skip]
1548 let buffer = [
1549 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1555 let error =
1556 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1557 .expect_err("Parsed successfully with an unrecognized option type");
1558 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1559 pointer,
1560 must_send_icmp,
1561 action,
1562 } = error
1563 {
1564 assert_eq!(pointer, 8);
1565 assert!(must_send_icmp);
1566 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1567 } else {
1568 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1569 }
1570
1571 let context =
1573 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1574 #[rustfmt::skip]
1575 let buffer = [
1576 IpProto::Tcp.into(), 0, 5, 3, 0, 0, 0, 0, ];
1581 let error =
1582 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1583 .expect_err(
1584 "Should fail to parse the header because one of the option is malformed",
1585 );
1586 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, .. } = error {
1587 assert_eq!(pointer, 3);
1588 } else {
1589 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1590 }
1591 }
1592
1593 #[test]
1594 fn test_routing_ext_hdr() {
1595 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1597 #[rustfmt::skip]
1598 let buffer = [
1599 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,
1606 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1607
1608 ];
1609 let ext_hdrs =
1610 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1611 .unwrap();
1612 assert_eq!(ext_hdrs.iter().count(), 0);
1613 }
1614
1615 #[test]
1616 fn test_routing_ext_hdr_err() {
1617 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1621 #[rustfmt::skip]
1622 let buffer = [
1623 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,
1630 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1631 ];
1632 let error =
1633 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1634 .expect_err("Parsed successfully when the routing type was set to 0");
1635 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1636 error
1637 {
1638 assert_eq!(pointer, 2);
1639 assert!(must_send_icmp);
1640 } else {
1641 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1642 }
1643
1644 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1646 #[rustfmt::skip]
1647 let buffer = [
1648 255, 4, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1655 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1656
1657 ];
1658 let error =
1659 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1660 .expect_err("Parsed successfully when the next header was invalid");
1661 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1662 error
1663 {
1664 assert_eq!(pointer, 0);
1665 assert!(!must_send_icmp);
1666 } else {
1667 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1668 }
1669
1670 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1672 #[rustfmt::skip]
1673 let buffer = [
1674 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,
1681 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1682
1683 ];
1684 let error =
1685 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1686 .expect_err("Parsed successfully with an unrecognized routing type");
1687 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1688 error
1689 {
1690 assert_eq!(pointer, 2);
1692 assert!(must_send_icmp);
1693 } else {
1694 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1695 }
1696 }
1697
1698 #[test]
1699 fn test_fragment_ext_hdr() {
1700 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1702 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1703 let identification: u32 = 3266246449;
1704 #[rustfmt::skip]
1705 let buffer = [
1706 IpProto::Tcp.into(), 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1712 ((identification >> 16) & 0xFF) as u8,
1713 ((identification >> 8) & 0xFF) as u8,
1714 (identification & 0xFF) as u8,
1715 ];
1716 let ext_hdrs =
1717 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1718 .unwrap();
1719 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1720 assert_eq!(ext_hdrs.len(), 1);
1721 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1722
1723 if let Ipv6ExtensionHeaderData::Fragment { fragment_data } = ext_hdrs[0].data() {
1724 assert_eq!(fragment_data.fragment_offset().into_raw(), 5063);
1725 assert_eq!(fragment_data.m_flag(), true);
1726 assert_eq!(fragment_data.identification(), 3266246449);
1727 } else {
1728 panic!("Should have matched Fragment: {:?}", ext_hdrs[0].data());
1729 }
1730 }
1731
1732 #[test]
1733 fn test_fragment_ext_hdr_err() {
1734 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1738 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1739 let identification: u32 = 3266246449;
1740 #[rustfmt::skip]
1741 let buffer = [
1742 255, 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1748 ((identification >> 16) & 0xFF) as u8,
1749 ((identification >> 8) & 0xFF) as u8,
1750 (identification & 0xFF) as u8,
1751 ];
1752 let error =
1753 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1754 .expect_err("Parsed successfully when the next header was invalid");
1755 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1756 error
1757 {
1758 assert_eq!(pointer, 0);
1759 assert!(!must_send_icmp);
1760 } else {
1761 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1762 }
1763 }
1764
1765 #[test]
1766 fn test_no_next_header_ext_hdr() {
1767 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6Proto::NoNextHeader.into());
1769 #[rustfmt::skip]
1770 let buffer = [0, 0, 0, 0,];
1771 let ext_hdrs =
1772 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1773 .unwrap();
1774 assert_eq!(ext_hdrs.iter().count(), 0);
1775 }
1776
1777 #[test]
1778 fn test_destination_options_ext_hdr() {
1779 let context =
1782 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1783 #[rustfmt::skip]
1784 let buffer = [
1785 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1790 let ext_hdrs =
1791 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1792 .unwrap();
1793 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1794 assert_eq!(ext_hdrs.len(), 1);
1795 assert_eq!(ext_hdrs[0].next_header, IpProto::Tcp.into());
1796 if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[0].data() {
1797 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1799 assert_eq!(options.len(), 1);
1800 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1801 } else {
1802 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[0].data());
1803 }
1804 }
1805
1806 #[test]
1807 fn test_destination_options_ext_hdr_err() {
1808 let context =
1810 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1811
1812 #[rustfmt::skip]
1814 let buffer = [
1815 255, 0, 1, 4, 0, 0, 0, 0, ];
1819 let error =
1820 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1821 .expect_err("Parsed successfully when the next header was invalid");
1822 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1823 error
1824 {
1825 assert_eq!(pointer, 0);
1826 assert!(!must_send_icmp);
1827 } else {
1828 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1829 }
1830
1831 let context =
1833 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1834 #[rustfmt::skip]
1835 let buffer = [
1836 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1841 let error =
1842 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1843 .expect_err("Parsed successfully with an unrecognized option type");
1844 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1845 pointer,
1846 must_send_icmp,
1847 action,
1848 } = error
1849 {
1850 assert_eq!(pointer, 8);
1851 assert!(must_send_icmp);
1852 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1853 } else {
1854 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1855 }
1856
1857 let context =
1859 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1860 #[rustfmt::skip]
1861 let buffer = [
1862 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1867 let error =
1868 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1869 .expect_err("Parsed successfully with an unrecognized option type");
1870 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1871 pointer,
1872 must_send_icmp,
1873 action,
1874 } = error
1875 {
1876 assert_eq!(pointer, 8);
1877 assert!(must_send_icmp);
1878 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1879 } else {
1880 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1881 }
1882
1883 let context =
1885 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1886 #[rustfmt::skip]
1887 let buffer = [
1888 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 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, 8);
1904 assert!(must_send_icmp);
1905 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1906 } else {
1907 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1908 }
1909 }
1910
1911 #[test]
1912 fn test_multiple_ext_hdrs() {
1913 let context =
1915 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1916 #[rustfmt::skip]
1917 let buffer = [
1918 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,
1933 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1934
1935 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1943 let ext_hdrs =
1944 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1945 .unwrap();
1946
1947 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1948 assert_eq!(ext_hdrs.len(), 2);
1949
1950 assert_eq!(ext_hdrs[0].next_header, Ipv6ExtHdrType::Routing.into());
1952 if let Ipv6ExtensionHeaderData::HopByHopOptions { options } = ext_hdrs[0].data() {
1953 assert_eq!(options.iter().count(), 0);
1955 } else {
1956 panic!("Should have matched HopByHopOptions: {:?}", ext_hdrs[0].data());
1957 }
1958
1959 assert_eq!(ext_hdrs[1].next_header, IpProto::Tcp.into());
1964 if let Ipv6ExtensionHeaderData::DestinationOptions { options } = ext_hdrs[1].data() {
1965 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1967 assert_eq!(options.len(), 1);
1968 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1969 } else {
1970 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[2].data());
1971 }
1972 }
1973
1974 #[test]
1975 fn test_multiple_ext_hdrs_errs() {
1976 let context =
1980 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1981 #[rustfmt::skip]
1982 let buffer = [
1983 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,
1998 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1999
2000 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
2008 let error =
2009 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2010 .expect_err("Parsed successfully when the next header was invalid");
2011 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2012 error
2013 {
2014 assert_eq!(pointer, 8);
2015 assert!(!must_send_icmp);
2016 } else {
2017 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2018 }
2019
2020 let context =
2022 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2023 #[rustfmt::skip]
2024 let buffer = [
2025 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,
2033 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2034
2035 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, ];
2050 let error =
2051 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2052 .expect_err("Parsed successfully when a hop by hop extension header was not the fist extension header");
2053 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2054 error
2055 {
2056 assert_eq!(pointer, 0);
2057 assert!(!must_send_icmp);
2058 } else {
2059 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2060 }
2061
2062 let context =
2065 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2066 #[rustfmt::skip]
2067 let buffer = [
2068 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, ];
2083 let error =
2084 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2085 .expect_err("Parsed successfully with an unrecognized destination option type");
2086 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
2087 pointer,
2088 must_send_icmp,
2089 action,
2090 } = error
2091 {
2092 assert_eq!(pointer, 16);
2093 assert!(must_send_icmp);
2094 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
2095 } else {
2096 panic!("Should have matched with UnrecognizedOption: {:?}", error);
2097 }
2098 }
2099
2100 #[test]
2101 fn test_serialize_hbh_router_alert() {
2102 let mut buffer = [0u8; 4];
2103 let option = HopByHopOption {
2104 action: ExtensionHeaderOptionAction::SkipAndContinue,
2105 mutable: false,
2106 data: HopByHopOptionData::RouterAlert { data: 0 },
2107 };
2108 <HopByHopOption<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
2109 assert_eq!(&buffer[..], &[5, 2, 0, 0]);
2110 }
2111
2112 #[test]
2113 fn test_parse_hbh_router_alert() {
2114 let context = ExtensionHeaderOptionContext::new();
2116 let buffer = [5, 2, 0, 0];
2117
2118 let options =
2119 Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context).unwrap();
2120 let rtralrt = options.iter().next().unwrap();
2121 assert!(!rtralrt.mutable);
2122 assert_eq!(rtralrt.action, ExtensionHeaderOptionAction::SkipAndContinue);
2123 assert_eq!(rtralrt.data, HopByHopOptionData::RouterAlert { data: 0 });
2124
2125 let result = <HopByHopOptionDataImpl as ExtensionHeaderOptionDataImpl>::parse_option(
2127 5,
2128 &buffer[1..],
2129 &mut (),
2130 false,
2131 );
2132 assert_eq!(result, ExtensionHeaderOptionDataParseResult::ErrorAt(1));
2133
2134 let context = ExtensionHeaderOptionContext::new();
2135 let buffer = [5, 3, 0, 0, 0];
2136
2137 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2138 .expect_err(
2139 "Parsing a malformed option with recognized kind but with wrong data should fail",
2140 );
2141 assert_eq!(error, ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer: 1 });
2142 }
2143
2144 fn trivial_hbh_options(lengths: &[Option<usize>]) -> Vec<HopByHopOption<'static>> {
2151 static ZEROES: [u8; 16] = [0u8; 16];
2152 lengths
2153 .iter()
2154 .map(|l| HopByHopOption {
2155 mutable: false,
2156 action: ExtensionHeaderOptionAction::SkipAndContinue,
2157 data: match l {
2158 Some(l) => HopByHopOptionData::Unrecognized {
2159 kind: 1,
2160 len: (*l - 2) as u8,
2161 data: &ZEROES[0..*l - 2],
2162 },
2163 None => HopByHopOptionData::RouterAlert { data: 0 },
2164 },
2165 })
2166 .collect()
2167 }
2168
2169 #[test]
2170 fn test_aligned_records_serializer() {
2171 for i in 2..12 {
2173 let options = trivial_hbh_options(&[Some(i), None]);
2174 let ser = AlignedRecordSequenceBuilder::<
2175 ExtensionHeaderOption<HopByHopOptionData<'_>>,
2176 _,
2177 >::new(2, options.iter());
2178 let mut buf = [0u8; 16];
2179 ser.serialize_into(&mut buf[0..16]);
2180 let base = (i + 1) & !1;
2181 assert_eq!(&buf[base..base + 4], &[5, 2, 0, 0]);
2183 }
2184 }
2185}