1use core::convert::Infallible as Never;
12use core::marker::PhantomData;
13
14use byteorder::{ByteOrder, NetworkEndian};
15use packet::records::options::{
16 AlignedOptionBuilder, LengthEncoding, OptionBuilder, OptionLayout, OptionParseErr,
17 OptionParseLayout,
18};
19use packet::records::{
20 ParsedRecord, RecordParseResult, Records, RecordsContext, RecordsImpl, RecordsImplLayout,
21 RecordsRawImpl,
22};
23use packet::{BufferView, BufferViewMut};
24use zerocopy::byteorder::network_endian::U16;
25
26use crate::ip::{FragmentOffset, IpProto, Ipv6ExtHdrType, Ipv6Proto};
27
28use crate::ipv6::{IPV6_FIXED_HDR_LEN, NEXT_HEADER_OFFSET};
29
30pub(crate) const IPV6_FRAGMENT_EXT_HDR_LEN: usize = 8;
32
33#[allow(missing_docs)]
35#[derive(Debug)]
36pub enum Ipv6ExtensionHeader<'a> {
37 HopByHopOptions { options: HopByHopOptionsData<'a> },
38 Routing { routing_data: RoutingData<'a> },
39 Fragment { fragment_data: FragmentData },
40 DestinationOptions { options: DestinationOptionsData<'a> },
41}
42
43#[allow(missing_docs)]
49#[derive(Debug, PartialEq, Eq)]
50pub(super) enum Ipv6ExtensionHeaderParsingError {
51 ErroneousHeaderField { pointer: u32, must_send_icmp: bool },
57 UnrecognizedNextHeader { pointer: u32, must_send_icmp: bool },
58 UnrecognizedOption { pointer: u32, must_send_icmp: bool, action: ExtensionHeaderOptionAction },
59 BufferExhausted,
60 MalformedData,
61}
62
63impl From<Never> for Ipv6ExtensionHeaderParsingError {
64 fn from(err: Never) -> Ipv6ExtensionHeaderParsingError {
65 match err {}
66 }
67}
68
69#[derive(Debug, Clone)]
71pub(super) struct Ipv6ExtensionHeaderParsingContext {
72 pub(super) next_header: u8,
76
77 iter: bool,
79
80 headers_parsed: usize,
82
83 pub(super) position: usize,
85
86 pub(super) next_header_offset: usize,
88}
89
90impl Ipv6ExtensionHeaderParsingContext {
91 pub(super) fn new(next_header: u8) -> Ipv6ExtensionHeaderParsingContext {
94 Ipv6ExtensionHeaderParsingContext {
95 iter: false,
96 headers_parsed: 0,
97 next_header,
98 next_header_offset: NEXT_HEADER_OFFSET.into(),
99 position: IPV6_FIXED_HDR_LEN,
100 }
101 }
102}
103
104impl RecordsContext for Ipv6ExtensionHeaderParsingContext {
105 fn clone_for_iter(&self) -> Self {
106 let mut ret = self.clone();
107 ret.iter = true;
108 ret
109 }
110}
111
112#[derive(Debug)]
114pub(super) struct Ipv6ExtensionHeaderImpl;
115
116impl Ipv6ExtensionHeaderImpl {
117 fn parse_next_hdr_and_len<'a, BV: BufferView<&'a [u8]>>(
123 data: &mut BV,
124 context: &mut Ipv6ExtensionHeaderParsingContext,
125 ) -> Result<u8, Ipv6ExtensionHeaderParsingError> {
126 let next_header =
127 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
128 let hdr_ext_len =
129 data.take_byte_front().ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
130
131 context.next_header = next_header;
132 context.next_header_offset = context.position;
133 context.position += 2;
134
135 Ok(hdr_ext_len)
136 }
137
138 fn parse_hop_by_hop_options<'a, BV: BufferView<&'a [u8]>>(
143 data: &mut BV,
144 context: &mut Ipv6ExtensionHeaderParsingContext,
145 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
146 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
147
148 let expected_len = (hdr_ext_len as usize) * 8 + 6;
154
155 let options = data
156 .take_front(expected_len)
157 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
158
159 let options_context = ExtensionHeaderOptionContext::new(context.position);
160 let options = Records::parse_with_context(options, options_context)
161 .map_err(ext_hdr_opt_err_to_ext_hdr_err)?;
162 let options = HopByHopOptionsData::new(options);
163
164 context.position += expected_len;
166 context.headers_parsed += 1;
167
168 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::HopByHopOptions { options }))
169 }
170
171 fn parse_routing<'a, BV: BufferView<&'a [u8]>>(
173 data: &mut BV,
174 context: &mut Ipv6ExtensionHeaderParsingContext,
175 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
176 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
177
178 let expected_len = (hdr_ext_len as usize) * 8 + 6;
184 let bytes = data
185 .take_front(expected_len)
186 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
187 let routing_data = RoutingData { bytes };
188
189 let segments_left = routing_data.segments_left();
190
191 if segments_left == 0 {
205 context.position += expected_len;
207 context.headers_parsed += 1;
208
209 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::Routing { routing_data }))
210 } else {
211 Err(Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
215 pointer: u32::try_from(context.position).unwrap(),
216 must_send_icmp: true,
217 })
218 }
219 }
220
221 fn parse_fragment<'a, BV: BufferView<&'a [u8]>>(
223 data: &mut BV,
224 context: &mut Ipv6ExtensionHeaderParsingContext,
225 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
226 if data.len() < 8 {
232 return Err(Ipv6ExtensionHeaderParsingError::BufferExhausted);
233 }
234
235 let _ = Self::parse_next_hdr_and_len(data, context)?;
239
240 context.position += 6;
242 context.headers_parsed += 1;
243
244 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::Fragment {
245 fragment_data: FragmentData { bytes: data.take_front(6).unwrap().try_into().unwrap() },
251 }))
252 }
253
254 fn parse_destination_options<'a, BV: BufferView<&'a [u8]>>(
256 data: &mut BV,
257 context: &mut Ipv6ExtensionHeaderParsingContext,
258 ) -> Result<ParsedRecord<Ipv6ExtensionHeader<'a>>, Ipv6ExtensionHeaderParsingError> {
259 let hdr_ext_len = Self::parse_next_hdr_and_len(data, context)?;
260
261 let expected_len = (hdr_ext_len as usize) * 8 + 6;
265
266 let options = data
267 .take_front(expected_len)
268 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
269
270 let options_context = ExtensionHeaderOptionContext::new(context.position);
271 let options = Records::parse_with_context(options, options_context)
272 .map_err(ext_hdr_opt_err_to_ext_hdr_err)?;
273 let options = DestinationOptionsData::new(options);
274
275 context.position += expected_len;
277 context.headers_parsed += 1;
278
279 Ok(ParsedRecord::Parsed(Ipv6ExtensionHeader::DestinationOptions { options }))
280 }
281}
282
283impl RecordsImplLayout for Ipv6ExtensionHeaderImpl {
284 type Context = Ipv6ExtensionHeaderParsingContext;
285 type Error = Ipv6ExtensionHeaderParsingError;
286}
287
288impl RecordsImpl for Ipv6ExtensionHeaderImpl {
289 type Record<'a> = Ipv6ExtensionHeader<'a>;
290
291 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
292 data: &mut BV,
293 context: &mut Self::Context,
294 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
295 let expected_hdr = context.next_header;
296
297 match Ipv6ExtHdrType::from(expected_hdr) {
298 Ipv6ExtHdrType::HopByHopOptions => {
299 if context.headers_parsed == 0 {
300 Self::parse_hop_by_hop_options(data, context)
301 } else {
302 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
304 pointer: context.next_header_offset as u32,
305 must_send_icmp: false,
306 })
307 }
308 }
309 Ipv6ExtHdrType::Routing => Self::parse_routing(data, context),
310 Ipv6ExtHdrType::Fragment => Self::parse_fragment(data, context),
311 Ipv6ExtHdrType::DestinationOptions => Self::parse_destination_options(data, context),
312 Ipv6ExtHdrType::EncapsulatingSecurityPayload | Ipv6ExtHdrType::Authentication => {
313 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
325 pointer: context.next_header_offset as u32,
326 must_send_icmp: false,
329 })
330 }
331 Ipv6ExtHdrType::Other(_) if is_valid_next_header_upper_layer(expected_hdr) => {
332 Ok(ParsedRecord::Done)
335 }
336 Ipv6ExtHdrType::Other(_) => {
337 Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
338 pointer: context.next_header_offset as u32,
339 must_send_icmp: false,
340 })
341 }
342 }
343 }
344}
345
346impl<'a> RecordsRawImpl<'a> for Ipv6ExtensionHeaderImpl {
347 fn parse_raw_with_context<BV: BufferView<&'a [u8]>>(
348 data: &mut BV,
349 context: &mut Self::Context,
350 ) -> Result<bool, Self::Error> {
351 let (next, skip) = match Ipv6ExtHdrType::from(context.next_header) {
352 Ipv6ExtHdrType::HopByHopOptions => {
353 if context.headers_parsed == 0 {
354 data.take_front(2)
357 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
358 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
359 } else {
360 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
362 pointer: context.next_header_offset as u32,
363 must_send_icmp: false,
364 });
365 }
366 }
367
368 Ipv6ExtHdrType::Routing | Ipv6ExtHdrType::DestinationOptions => {
369 data.take_front(2)
372 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
373 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
374 }
375 Ipv6ExtHdrType::Fragment => {
376 (
378 data.take_byte_front()
379 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?,
380 7,
381 )
382 }
383 Ipv6ExtHdrType::EncapsulatingSecurityPayload => {
384 return debug_err!(
388 Err(Ipv6ExtensionHeaderParsingError::MalformedData),
389 "ESP extension header not supported"
390 );
391 }
392 Ipv6ExtHdrType::Authentication => {
393 data.take_front(2)
397 .map(|x| (x[0], (x[1] as usize + 2) * 4 - 2))
398 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
399 }
400 Ipv6ExtHdrType::Other(next_header) if is_valid_next_header_upper_layer(next_header) => {
401 return Ok(false);
402 }
403
404 Ipv6ExtHdrType::Other(_) => {
405 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
406 pointer: context.next_header_offset as u32,
407 must_send_icmp: false,
408 });
409 }
410 };
411 let _: &[u8] =
412 data.take_front(skip).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
413 context.next_header = next;
414 context.next_header_offset = context.position;
415 context.position += skip;
416 context.headers_parsed += 1;
417 Ok(true)
418 }
419}
420
421#[derive(Debug)]
427pub struct HopByHopOptionsData<'a> {
428 options: Records<&'a [u8], HopByHopOptionsImpl>,
429}
430
431impl<'a> HopByHopOptionsData<'a> {
432 fn new(options: Records<&'a [u8], HopByHopOptionsImpl>) -> HopByHopOptionsData<'a> {
434 HopByHopOptionsData { options }
435 }
436
437 pub fn iter(&'a self) -> impl Iterator<Item = HopByHopOption<'a>> {
440 self.options.iter()
441 }
442}
443
444pub type HopByHopOption<'a> = ExtensionHeaderOption<HopByHopOptionData<'a>>;
446
447pub(super) type HopByHopOptionsImpl = ExtensionHeaderOptionImpl<HopByHopOptionDataImpl>;
450
451const HBH_OPTION_KIND_RTRALRT: u8 = 5;
455
456const HBH_OPTION_RTRALRT_LEN: usize = 2;
460
461#[allow(missing_docs)]
463#[derive(Debug, PartialEq, Eq, Clone)]
464pub enum HopByHopOptionData<'a> {
465 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
466 RouterAlert { data: u16 },
467}
468
469#[derive(Debug)]
471pub(super) struct HopByHopOptionDataImpl;
472
473impl ExtensionHeaderOptionDataImplLayout for HopByHopOptionDataImpl {
474 type Context = ();
475}
476
477impl ExtensionHeaderOptionDataImpl for HopByHopOptionDataImpl {
478 type OptionData<'a> = HopByHopOptionData<'a>;
479
480 fn parse_option<'a>(
481 kind: u8,
482 data: &'a [u8],
483 _context: &mut Self::Context,
484 allow_unrecognized: bool,
485 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
486 match kind {
487 HBH_OPTION_KIND_RTRALRT => {
488 if data.len() == HBH_OPTION_RTRALRT_LEN {
489 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::RouterAlert {
490 data: NetworkEndian::read_u16(data),
491 })
492 } else {
493 ExtensionHeaderOptionDataParseResult::ErrorAt(1)
496 }
497 }
498 _ => {
499 if allow_unrecognized {
500 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::Unrecognized {
501 kind,
502 len: data.len() as u8,
503 data,
504 })
505 } else {
506 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
507 }
508 }
509 }
510 }
511}
512
513impl OptionLayout for HopByHopOptionsImpl {
514 type KindLenField = u8;
515 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
516}
517
518impl OptionParseLayout for HopByHopOptionsImpl {
519 type Error = OptionParseErr;
520 const END_OF_OPTIONS: Option<u8> = Some(0);
521 const NOP: Option<u8> = Some(1);
522}
523
524#[doc(hidden)]
530pub enum HopByHopOptionLayout {}
531
532impl OptionLayout for HopByHopOptionLayout {
533 type KindLenField = u8;
534 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
535}
536
537impl<'a> OptionBuilder for HopByHopOption<'a> {
538 type Layout = HopByHopOptionLayout;
539 fn serialized_len(&self) -> usize {
540 match self.data {
541 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_RTRALRT_LEN,
542 HopByHopOptionData::Unrecognized { len, .. } => len as usize,
543 }
544 }
545
546 fn option_kind(&self) -> u8 {
547 let action: u8 = self.action.into();
548 let mutable = self.mutable as u8;
549 let type_number = match self.data {
550 HopByHopOptionData::Unrecognized { kind, .. } => kind,
551 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_KIND_RTRALRT,
552 };
553 (action << 6) | (mutable << 5) | type_number
554 }
555
556 fn serialize_into(&self, mut buffer: &mut [u8]) {
557 match self.data {
558 HopByHopOptionData::Unrecognized { data, .. } => buffer.copy_from_slice(data),
559 HopByHopOptionData::RouterAlert { data } => {
560 (&mut buffer).write_obj_front(&U16::new(data)).unwrap()
563 }
564 }
565 }
566}
567
568impl<'a> AlignedOptionBuilder for HopByHopOption<'a> {
569 fn alignment_requirement(&self) -> (usize, usize) {
570 match self.data {
571 HopByHopOptionData::RouterAlert { .. } => (2, 0),
574 _ => (1, 0),
575 }
576 }
577
578 fn serialize_padding(buf: &mut [u8], length: usize) {
579 assert!(length <= buf.len());
580 assert!(length <= (core::u8::MAX as usize) + 2);
581
582 #[allow(clippy::comparison_chain)]
583 if length == 1 {
584 buf[0] = 0
586 } else if length > 1 {
587 buf[0] = 1;
589 buf[1] = (length - 2) as u8;
590 #[allow(clippy::needless_range_loop)]
591 for i in 2..length {
592 buf[i] = 0
593 }
594 }
595 }
596}
597
598#[derive(Debug)]
618pub struct RoutingData<'a> {
619 bytes: &'a [u8],
620}
621
622#[derive(Debug, PartialEq, Eq)]
624pub enum RoutingType {}
625
626#[derive(Debug, PartialEq, Eq)]
628pub enum RoutingTypeParseError {
629 UnsupportedType(u8),
632}
633
634impl TryFrom<u8> for RoutingType {
635 type Error = RoutingTypeParseError;
636
637 fn try_from(value: u8) -> Result<Self, Self::Error> {
638 Err(RoutingTypeParseError::UnsupportedType(value))
639 }
640}
641
642impl<'a> RoutingData<'a> {
643 pub fn routing_type(&self) -> Result<RoutingType, RoutingTypeParseError> {
645 debug_assert!(self.bytes.len() >= 6);
646 RoutingType::try_from(self.bytes[0])
647 }
648
649 pub fn segments_left(&self) -> u8 {
651 debug_assert!(self.bytes.len() >= 6);
652 self.bytes[1]
653 }
654}
655
656#[derive(Debug, Copy, Clone)]
672pub struct FragmentData {
673 bytes: [u8; 6],
674}
675
676impl FragmentData {
677 pub fn fragment_offset(&self) -> FragmentOffset {
679 FragmentOffset::new_with_msb(U16::from_bytes([self.bytes[0], self.bytes[1]]).get())
680 }
681
682 pub fn m_flag(&self) -> bool {
684 (self.bytes[1] & 0x1) == 0x01
685 }
686
687 pub fn identification(&self) -> u32 {
689 NetworkEndian::read_u32(&self.bytes[2..6])
690 }
691}
692
693#[derive(Debug)]
699pub struct DestinationOptionsData<'a> {
700 options: Records<&'a [u8], DestinationOptionsImpl>,
701}
702
703impl<'a> DestinationOptionsData<'a> {
704 fn new(options: Records<&'a [u8], DestinationOptionsImpl>) -> DestinationOptionsData<'a> {
706 DestinationOptionsData { options }
707 }
708
709 pub fn iter(&'a self) -> impl Iterator<Item = DestinationOption<'a>> {
712 self.options.iter()
713 }
714}
715
716pub type DestinationOption<'a> = ExtensionHeaderOption<DestinationOptionData<'a>>;
718
719pub(super) type DestinationOptionsImpl = ExtensionHeaderOptionImpl<DestinationOptionDataImpl>;
722
723#[allow(missing_docs)]
725#[derive(Debug)]
726pub enum DestinationOptionData<'a> {
727 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
728}
729
730#[derive(Debug)]
732pub(super) struct DestinationOptionDataImpl;
733
734impl ExtensionHeaderOptionDataImplLayout for DestinationOptionDataImpl {
735 type Context = ();
736}
737
738impl ExtensionHeaderOptionDataImpl for DestinationOptionDataImpl {
739 type OptionData<'a> = DestinationOptionData<'a>;
740
741 fn parse_option<'a>(
742 kind: u8,
743 data: &'a [u8],
744 _context: &mut Self::Context,
745 allow_unrecognized: bool,
746 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
747 if allow_unrecognized {
748 ExtensionHeaderOptionDataParseResult::Ok(DestinationOptionData::Unrecognized {
749 kind,
750 len: data.len() as u8,
751 data,
752 })
753 } else {
754 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
755 }
756 }
757}
758
759#[derive(Debug, Clone)]
765pub(super) struct ExtensionHeaderOptionContext<C: Sized + Clone> {
766 options_parsed: usize,
768
769 position: usize,
771
772 specific_context: C,
774}
775
776impl<C: Sized + Clone + Default> ExtensionHeaderOptionContext<C> {
777 fn new(offset: usize) -> Self {
778 ExtensionHeaderOptionContext {
779 options_parsed: 0,
780 position: offset,
781 specific_context: C::default(),
782 }
783 }
784}
785
786impl<C: Sized + Clone> RecordsContext for ExtensionHeaderOptionContext<C> {}
787
788pub(super) trait ExtensionHeaderOptionDataImplLayout {
790 type Context: RecordsContext;
793}
794
795#[derive(PartialEq, Eq, Debug)]
797pub enum ExtensionHeaderOptionDataParseResult<D> {
798 Ok(D),
800
801 ErrorAt(u32),
807
808 UnrecognizedKind,
810}
811
812pub(super) trait ExtensionHeaderOptionDataImpl: ExtensionHeaderOptionDataImplLayout {
814 type OptionData<'a>: Sized;
820
821 fn parse_option<'a>(
832 kind: u8,
833 data: &'a [u8],
834 context: &mut Self::Context,
835 allow_unrecognized: bool,
836 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>>;
837}
838
839#[derive(Debug)]
846pub(super) struct ExtensionHeaderOptionImpl<O>(PhantomData<O>);
847
848impl<O> ExtensionHeaderOptionImpl<O> {
849 const PAD1: u8 = 0;
850 const PADN: u8 = 1;
851}
852
853impl<O> RecordsImplLayout for ExtensionHeaderOptionImpl<O>
854where
855 O: ExtensionHeaderOptionDataImplLayout,
856{
857 type Error = ExtensionHeaderOptionParsingError;
858 type Context = ExtensionHeaderOptionContext<O::Context>;
859}
860
861impl<O> RecordsImpl for ExtensionHeaderOptionImpl<O>
862where
863 O: ExtensionHeaderOptionDataImpl,
864{
865 type Record<'a> = ExtensionHeaderOption<O::OptionData<'a>>;
866
867 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
868 data: &mut BV,
869 context: &mut Self::Context,
870 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
871 let kind = match data.take_byte_front() {
873 None => return Ok(ParsedRecord::Done),
874 Some(k) => k,
875 };
876
877 let action =
881 ExtensionHeaderOptionAction::try_from((kind >> 6) & 0x3).expect("Unexpected error");
882 let mutable = ((kind >> 5) & 0x1) == 0x1;
883 if kind == Self::PAD1 {
889 context.options_parsed += 1;
891 context.position += 1;
892
893 return Ok(ParsedRecord::Skipped);
894 }
895
896 let len =
897 data.take_byte_front().ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
898
899 let data = data
900 .take_front(len as usize)
901 .ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
902
903 if kind == Self::PADN {
905 context.options_parsed += 1;
907 context.position += 2 + (len as usize);
908
909 return Ok(ParsedRecord::Skipped);
910 }
911
912 match O::parse_option(
914 kind,
915 data,
916 &mut context.specific_context,
917 action == ExtensionHeaderOptionAction::SkipAndContinue,
918 ) {
919 ExtensionHeaderOptionDataParseResult::Ok(o) => {
920 context.options_parsed += 1;
922 context.position += 2 + (len as usize);
923
924 Ok(ParsedRecord::Parsed(ExtensionHeaderOption { action, mutable, data: o }))
925 }
926 ExtensionHeaderOptionDataParseResult::ErrorAt(offset) => {
927 Err(ExtensionHeaderOptionParsingError::ErroneousOptionField {
932 pointer: u32::try_from(context.position + offset as usize).unwrap(),
933 })
934 }
935 ExtensionHeaderOptionDataParseResult::UnrecognizedKind => {
936 match action {
938 ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
945 "Should never end up here since action was set to skip and continue"
946 ),
947 _ => Err(ExtensionHeaderOptionParsingError::UnrecognizedOption {
958 pointer: u32::try_from(context.position).unwrap(),
959 action,
960 }),
961 }
962 }
963 }
964 }
965}
966
967#[allow(missing_docs)]
969#[derive(Debug, PartialEq, Eq)]
970pub(crate) enum ExtensionHeaderOptionParsingError {
971 ErroneousOptionField { pointer: u32 },
972 UnrecognizedOption { pointer: u32, action: ExtensionHeaderOptionAction },
973 BufferExhausted,
974}
975
976impl From<Never> for ExtensionHeaderOptionParsingError {
977 fn from(err: Never) -> ExtensionHeaderOptionParsingError {
978 match err {}
979 }
980}
981
982#[derive(Debug, PartialEq, Eq, Clone, Copy)]
988pub enum ExtensionHeaderOptionAction {
989 SkipAndContinue,
992
993 DiscardPacket,
996
997 DiscardPacketSendIcmp,
1003
1004 DiscardPacketSendIcmpNoMulticast,
1010}
1011
1012impl TryFrom<u8> for ExtensionHeaderOptionAction {
1013 type Error = ();
1014
1015 fn try_from(value: u8) -> Result<Self, ()> {
1016 match value {
1017 0 => Ok(ExtensionHeaderOptionAction::SkipAndContinue),
1018 1 => Ok(ExtensionHeaderOptionAction::DiscardPacket),
1019 2 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmp),
1020 3 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast),
1021 _ => Err(()),
1022 }
1023 }
1024}
1025
1026impl From<ExtensionHeaderOptionAction> for u8 {
1027 fn from(a: ExtensionHeaderOptionAction) -> u8 {
1028 match a {
1029 ExtensionHeaderOptionAction::SkipAndContinue => 0,
1030 ExtensionHeaderOptionAction::DiscardPacket => 1,
1031 ExtensionHeaderOptionAction::DiscardPacketSendIcmp => 2,
1032 ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => 3,
1033 }
1034 }
1035}
1036
1037#[derive(PartialEq, Eq, Debug, Clone)]
1043pub struct ExtensionHeaderOption<O> {
1044 pub action: ExtensionHeaderOptionAction,
1046
1047 pub mutable: bool,
1053
1054 pub data: O,
1056}
1057
1058pub(super) fn is_valid_next_header_upper_layer(next_header: u8) -> bool {
1067 match Ipv6Proto::from(next_header) {
1068 Ipv6Proto::Proto(IpProto::Tcp)
1069 | Ipv6Proto::Proto(IpProto::Udp)
1070 | Ipv6Proto::Icmpv6
1071 | Ipv6Proto::NoNextHeader => true,
1072 Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => false,
1073 }
1074}
1075
1076fn ext_hdr_opt_err_to_ext_hdr_err(
1082 err: ExtensionHeaderOptionParsingError,
1083) -> Ipv6ExtensionHeaderParsingError {
1084 match err {
1085 ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer } => {
1086 Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1087 pointer: pointer,
1088 must_send_icmp: false,
1093 }
1094 }
1095 ExtensionHeaderOptionParsingError::UnrecognizedOption { pointer, action } => {
1096 Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1097 pointer: pointer,
1098 must_send_icmp: true,
1099 action,
1100 }
1101 }
1102 ExtensionHeaderOptionParsingError::BufferExhausted => {
1103 Ipv6ExtensionHeaderParsingError::BufferExhausted
1104 }
1105 }
1106}
1107
1108#[cfg(test)]
1109mod tests {
1110 use packet::records::{AlignedRecordSequenceBuilder, RecordBuilder};
1111
1112 use crate::ip::Ipv4Proto;
1113 use crate::ipv6::IPV6_FIXED_HDR_LEN;
1114
1115 use super::*;
1116
1117 #[test]
1118 fn test_is_valid_next_header_upper_layer() {
1119 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1121 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1122
1123 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1125 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1126 }
1127
1128 #[test]
1129 fn test_hop_by_hop_options() {
1130 let buffer = [0; 10];
1132 let mut context = ExtensionHeaderOptionContext::new(10);
1133 let options =
1134 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1135 .unwrap();
1136 assert_eq!(options.iter().count(), 0);
1137 assert_eq!(context.position, 20);
1138 assert_eq!(context.options_parsed, 10);
1139
1140 #[rustfmt::skip]
1142 let buffer = [
1143 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1147 let mut context = ExtensionHeaderOptionContext::new(1);
1148 let options =
1149 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1150 .unwrap();
1151 assert_eq!(options.iter().count(), 0);
1152 assert_eq!(context.position, 14);
1153 assert_eq!(context.options_parsed, 3);
1154
1155 #[rustfmt::skip]
1158 let buffer = [
1159 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1163 let mut context = ExtensionHeaderOptionContext::new(1);
1164 let options =
1165 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1166 .unwrap();
1167 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1168 assert_eq!(options.len(), 1);
1169 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1170 assert_eq!(context.position, 13);
1171 assert_eq!(context.options_parsed, 3);
1172 }
1173
1174 #[test]
1175 fn test_hop_by_hop_options_err() {
1176 #[rustfmt::skip]
1178 let buffer = [
1179 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1183 let mut context = ExtensionHeaderOptionContext::new(5);
1184 assert_eq!(
1185 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1186 .expect_err("Parsed successfully when we were short 2 bytes"),
1187 ExtensionHeaderOptionParsingError::BufferExhausted
1188 );
1189 assert_eq!(context.position, 8);
1190 assert_eq!(context.options_parsed, 2);
1191
1192 #[rustfmt::skip]
1194 let buffer = [
1195 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1199 let mut context = ExtensionHeaderOptionContext::new(5);
1200 assert_eq!(
1201 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1202 .expect_err("Parsed successfully when we had an unrecognized option type"),
1203 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1204 pointer: 8,
1205 action: ExtensionHeaderOptionAction::DiscardPacket,
1206 }
1207 );
1208 assert_eq!(context.position, 8);
1209 assert_eq!(context.options_parsed, 1);
1210
1211 #[rustfmt::skip]
1214 let buffer = [
1215 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1220 let mut context = ExtensionHeaderOptionContext::new(5);
1221 assert_eq!(
1222 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1223 .expect_err("Parsed successfully when we had an unrecognized option type"),
1224 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1225 pointer: 8,
1226 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1227 }
1228 );
1229 assert_eq!(context.position, 8);
1230 assert_eq!(context.options_parsed, 1);
1231
1232 #[rustfmt::skip]
1235 let buffer = [
1236 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1241 let mut context = ExtensionHeaderOptionContext::new(5);
1242 assert_eq!(
1243 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1244 .expect_err("Parsed successfully when we had an unrecognized option type"),
1245 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1246 pointer: 8,
1247 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1248 }
1249 );
1250 assert_eq!(context.position, 8);
1251 assert_eq!(context.options_parsed, 1);
1252
1253 #[rustfmt::skip]
1255 let buffer = [
1256 0xC0,
1259 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1262 let mut context = ExtensionHeaderOptionContext::new(5);
1263 assert_eq!(
1264 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1265 .expect_err("Parsed successfully when we had Pad1 with upper bits set"),
1266 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1267 pointer: 5,
1268 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1269 }
1270 );
1271 assert_eq!(context.position, 5);
1272 assert_eq!(context.options_parsed, 0);
1273
1274 #[rustfmt::skip]
1276 let buffer = [
1277 0, 0xC1, 0,
1281 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1283 let mut context = ExtensionHeaderOptionContext::new(5);
1284 assert_eq!(
1285 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1286 .expect_err("Parsed successfully when we had Pad2 with upper bits set"),
1287 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1288 pointer: 6,
1289 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1290 }
1291 );
1292 assert_eq!(context.position, 6);
1293 assert_eq!(context.options_parsed, 1);
1294
1295 #[rustfmt::skip]
1297 let buffer = [
1298 0, 1, 0, 0xC1, 8, 0, 0, 0, 0, 0, 0, 0, 0,
1303 ];
1304 let mut context = ExtensionHeaderOptionContext::new(5);
1305 assert_eq!(
1306 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1307 .expect_err("Parsed successfully when we had PadN with upper bits set"),
1308 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1309 pointer: 8,
1310 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1311 }
1312 );
1313 assert_eq!(context.position, 8);
1314 assert_eq!(context.options_parsed, 2);
1315 }
1316
1317 #[test]
1318 fn test_destination_options() {
1319 let buffer = [0; 10];
1321 let mut context = ExtensionHeaderOptionContext::new(5);
1322 let options =
1323 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1324 .unwrap();
1325 assert_eq!(options.iter().count(), 0);
1326 assert_eq!(context.position, 15);
1327 assert_eq!(context.options_parsed, 10);
1328
1329 #[rustfmt::skip]
1331 let buffer = [
1332 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1336 let mut context = ExtensionHeaderOptionContext::new(5);
1337 let options =
1338 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1339 .unwrap();
1340 assert_eq!(options.iter().count(), 0);
1341 assert_eq!(context.position, 18);
1342 assert_eq!(context.options_parsed, 3);
1343
1344 #[rustfmt::skip]
1347 let buffer = [
1348 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1352 let mut context = ExtensionHeaderOptionContext::new(5);
1353 let options =
1354 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1355 .unwrap();
1356 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1357 assert_eq!(options.len(), 1);
1358 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1359 assert_eq!(context.position, 17);
1360 assert_eq!(context.options_parsed, 3);
1361 }
1362
1363 #[test]
1364 fn test_destination_options_err() {
1365 #[rustfmt::skip]
1367 let buffer = [
1368 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1372 let mut context = ExtensionHeaderOptionContext::new(5);
1373 assert_eq!(
1374 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1375 .expect_err("Parsed successfully when we were short 2 bytes"),
1376 ExtensionHeaderOptionParsingError::BufferExhausted
1377 );
1378 assert_eq!(context.position, 8);
1379 assert_eq!(context.options_parsed, 2);
1380
1381 #[rustfmt::skip]
1383 let buffer = [
1384 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1388 let mut context = ExtensionHeaderOptionContext::new(5);
1389 assert_eq!(
1390 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1391 .expect_err("Parsed successfully when we had an unrecognized option type"),
1392 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1393 pointer: 8,
1394 action: ExtensionHeaderOptionAction::DiscardPacket,
1395 }
1396 );
1397 assert_eq!(context.position, 8);
1398 assert_eq!(context.options_parsed, 1);
1399
1400 #[rustfmt::skip]
1403 let buffer = [
1404 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1409 let mut context = ExtensionHeaderOptionContext::new(5);
1410 assert_eq!(
1411 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1412 .expect_err("Parsed successfully when we had an unrecognized option type"),
1413 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1414 pointer: 8,
1415 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1416 }
1417 );
1418 assert_eq!(context.position, 8);
1419 assert_eq!(context.options_parsed, 1);
1420
1421 #[rustfmt::skip]
1424 let buffer = [
1425 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1430 let mut context = ExtensionHeaderOptionContext::new(5);
1431 assert_eq!(
1432 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1433 .expect_err("Parsed successfully when we had an unrecognized option type"),
1434 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1435 pointer: 8,
1436 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1437 }
1438 );
1439 assert_eq!(context.position, 8);
1440 assert_eq!(context.options_parsed, 1);
1441 }
1442
1443 #[test]
1444 fn test_hop_by_hop_options_ext_hdr() {
1445 let context =
1448 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1449 #[rustfmt::skip]
1450 let buffer = [
1451 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1456 let ext_hdrs =
1457 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1458 .unwrap();
1459 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1460 assert_eq!(ext_hdrs.len(), 1);
1461 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1462 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1464 assert_eq!(options.len(), 1);
1465 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1466 } else {
1467 panic!("Should have matched HopByHopOptions {:?}", ext_hdrs[0]);
1468 }
1469 }
1470
1471 #[test]
1472 fn test_hop_by_hop_options_ext_hdr_err() {
1473 let context =
1477 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1478 #[rustfmt::skip]
1479 let buffer = [
1480 255, 0, 1, 4, 0, 0, 0, 0, ];
1484 let error =
1485 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1486 .expect_err("Parsed successfully when the next header was invalid");
1487 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1488 error
1489 {
1490 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1491 assert!(!must_send_icmp);
1492 } else {
1493 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1494 }
1495
1496 let context =
1498 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1499 #[rustfmt::skip]
1500 let buffer = [
1501 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1506 let error =
1507 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1508 .expect_err("Parsed successfully with an unrecognized option type");
1509 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1510 pointer,
1511 must_send_icmp,
1512 action,
1513 } = error
1514 {
1515 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1516 assert!(must_send_icmp);
1517 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1518 } else {
1519 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1520 }
1521
1522 let context =
1524 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1525 #[rustfmt::skip]
1526 let buffer = [
1527 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1532 let error =
1533 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1534 .expect_err("Parsed successfully with an unrecognized option type");
1535 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1536 pointer,
1537 must_send_icmp,
1538 action,
1539 } = error
1540 {
1541 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1542 assert!(must_send_icmp);
1543 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1544 } else {
1545 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1546 }
1547
1548 let context =
1550 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1551 #[rustfmt::skip]
1552 let buffer = [
1553 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1559 let error =
1560 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1561 .expect_err("Parsed successfully with an unrecognized option type");
1562 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1563 pointer,
1564 must_send_icmp,
1565 action,
1566 } = error
1567 {
1568 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1569 assert!(must_send_icmp);
1570 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1571 } else {
1572 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1573 }
1574
1575 let context =
1577 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1578 #[rustfmt::skip]
1579 let buffer = [
1580 IpProto::Tcp.into(), 0, 5, 3, 0, 0, 0, 0, ];
1585 let error =
1586 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1587 .expect_err(
1588 "Should fail to parse the header because one of the option is malformed",
1589 );
1590 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, .. } = error {
1591 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 3);
1592 } else {
1593 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1594 }
1595 }
1596
1597 #[test]
1598 fn test_routing_ext_hdr() {
1599 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1601 #[rustfmt::skip]
1602 let buffer = [
1603 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,
1610 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1611
1612 ];
1613 let ext_hdrs =
1614 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1615 .unwrap();
1616 let results: Vec<_> = ext_hdrs.iter().collect();
1617 assert_eq!(results.len(), 1);
1618 if let Ipv6ExtensionHeader::Routing { routing_data } = &results[0] {
1619 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1620 assert_eq!(routing_data.segments_left(), 0);
1621 } else {
1622 panic!("Should have matched with RoutingExtensionHeader");
1623 }
1624 }
1625
1626 #[test]
1627 fn test_routing_ext_hdr_err() {
1628 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1632 #[rustfmt::skip]
1633 let buffer = [
1634 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,
1641 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1642 ];
1643 let error =
1644 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1645 .expect_err("Parsed successfully when the routing type was set to 0");
1646 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1647 error
1648 {
1649 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1650 assert!(must_send_icmp);
1651 } else {
1652 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1653 }
1654
1655 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1657 #[rustfmt::skip]
1658 let buffer = [
1659 255, 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1666 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1667
1668 ];
1669 let error =
1670 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1671 .expect_err("Parsed successfully when the next header was invalid");
1672 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1673 error
1674 {
1675 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1676 assert!(!must_send_icmp);
1677 } else {
1678 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1679 }
1680
1681 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1683 #[rustfmt::skip]
1684 let buffer = [
1685 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,
1692 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1693
1694 ];
1695 let error =
1696 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1697 .expect_err("Parsed successfully with an unrecognized routing type");
1698 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1699 error
1700 {
1701 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1703 assert!(must_send_icmp);
1704 } else {
1705 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1706 }
1707 }
1708
1709 #[test]
1710 fn test_fragment_ext_hdr() {
1711 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1713 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1714 let identification: u32 = 3266246449;
1715 #[rustfmt::skip]
1716 let buffer = [
1717 IpProto::Tcp.into(), 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1723 ((identification >> 16) & 0xFF) as u8,
1724 ((identification >> 8) & 0xFF) as u8,
1725 (identification & 0xFF) as u8,
1726 ];
1727 let ext_hdrs =
1728 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1729 .unwrap();
1730 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1731 assert_eq!(ext_hdrs.len(), 1);
1732
1733 if let Ipv6ExtensionHeader::Fragment { fragment_data } = &ext_hdrs[0] {
1734 assert_eq!(fragment_data.fragment_offset().into_raw(), 5063);
1735 assert_eq!(fragment_data.m_flag(), true);
1736 assert_eq!(fragment_data.identification(), 3266246449);
1737 } else {
1738 panic!("Should have matched Fragment: {:?}", &ext_hdrs[0]);
1739 }
1740 }
1741
1742 #[test]
1743 fn test_fragment_ext_hdr_err() {
1744 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1748 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1749 let identification: u32 = 3266246449;
1750 #[rustfmt::skip]
1751 let buffer = [
1752 255, 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1758 ((identification >> 16) & 0xFF) as u8,
1759 ((identification >> 8) & 0xFF) as u8,
1760 (identification & 0xFF) as u8,
1761 ];
1762 let error =
1763 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1764 .expect_err("Parsed successfully when the next header was invalid");
1765 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1766 error
1767 {
1768 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1769 assert!(!must_send_icmp);
1770 } else {
1771 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1772 }
1773 }
1774
1775 #[test]
1776 fn test_no_next_header_ext_hdr() {
1777 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6Proto::NoNextHeader.into());
1779 #[rustfmt::skip]
1780 let buffer = [0, 0, 0, 0,];
1781 let ext_hdrs =
1782 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1783 .unwrap();
1784 assert_eq!(ext_hdrs.iter().count(), 0);
1785 }
1786
1787 #[test]
1788 fn test_destination_options_ext_hdr() {
1789 let context =
1792 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1793 #[rustfmt::skip]
1794 let buffer = [
1795 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1800 let ext_hdrs =
1801 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1802 .unwrap();
1803 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1804 assert_eq!(ext_hdrs.len(), 1);
1805 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[0] {
1806 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1808 assert_eq!(options.len(), 1);
1809 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1810 } else {
1811 panic!("Should have matched DestinationOptions: {:?}", &ext_hdrs[0]);
1812 }
1813 }
1814
1815 #[test]
1816 fn test_destination_options_ext_hdr_err() {
1817 let context =
1819 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1820
1821 #[rustfmt::skip]
1823 let buffer = [
1824 255, 0, 1, 4, 0, 0, 0, 0, ];
1828 let error =
1829 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1830 .expect_err("Parsed successfully when the next header was invalid");
1831 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1832 error
1833 {
1834 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1835 assert!(!must_send_icmp);
1836 } else {
1837 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1838 }
1839
1840 let context =
1842 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1843 #[rustfmt::skip]
1844 let buffer = [
1845 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1850 let error =
1851 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1852 .expect_err("Parsed successfully with an unrecognized option type");
1853 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1854 pointer,
1855 must_send_icmp,
1856 action,
1857 } = error
1858 {
1859 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1860 assert!(must_send_icmp);
1861 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1862 } else {
1863 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1864 }
1865
1866 let context =
1868 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1869 #[rustfmt::skip]
1870 let buffer = [
1871 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1876 let error =
1877 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1878 .expect_err("Parsed successfully with an unrecognized option type");
1879 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1880 pointer,
1881 must_send_icmp,
1882 action,
1883 } = error
1884 {
1885 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1886 assert!(must_send_icmp);
1887 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1888 } else {
1889 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1890 }
1891
1892 let context =
1894 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1895 #[rustfmt::skip]
1896 let buffer = [
1897 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1903 let error =
1904 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1905 .expect_err("Parsed successfully with an unrecognized option type");
1906 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1907 pointer,
1908 must_send_icmp,
1909 action,
1910 } = error
1911 {
1912 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1913 assert!(must_send_icmp);
1914 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1915 } else {
1916 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1917 }
1918 }
1919
1920 #[test]
1921 fn test_multiple_ext_hdrs() {
1922 let context =
1924 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1925 #[rustfmt::skip]
1926 let buffer = [
1927 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,
1942 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1943
1944 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1952 let ext_hdrs =
1953 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1954 .unwrap();
1955
1956 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1957 assert_eq!(ext_hdrs.len(), 3);
1958
1959 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1961 assert_eq!(options.iter().count(), 0);
1963 } else {
1964 panic!("Should have matched HopByHopOptions: {:?}", &ext_hdrs[0]);
1965 }
1966
1967 if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1969 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1970 assert_eq!(routing_data.segments_left(), 0);
1971 } else {
1972 panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1973 }
1974
1975 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
1977 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1979 assert_eq!(options.len(), 1);
1980 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1981 } else {
1982 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[2]);
1983 }
1984 }
1985
1986 #[test]
1987 fn test_multiple_ext_hdrs_errs() {
1988 let context =
1992 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1993 #[rustfmt::skip]
1994 let buffer = [
1995 Ipv6ExtHdrType::Routing.into(), 0, 0, 1, 0, 1, 1, 0, 255, 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2010 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2011
2012 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
2020 let error =
2021 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2022 .expect_err("Parsed successfully when the next header was invalid");
2023 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2024 error
2025 {
2026 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
2027 assert!(!must_send_icmp);
2028 } else {
2029 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2030 }
2031
2032 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
2034 #[rustfmt::skip]
2035 let buffer = [
2036 Ipv6ExtHdrType::HopByHopOptions.into(), 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2044 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2045
2046 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, ];
2061 let error =
2062 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2063 .expect_err("Parsed successfully when a hop by hop extension header was not the fist extension header");
2064 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2065 error
2066 {
2067 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
2068 assert!(!must_send_icmp);
2069 } else {
2070 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2071 }
2072
2073 let context =
2076 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2077 #[rustfmt::skip]
2078 let buffer = [
2079 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, ];
2094 let error =
2095 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2096 .expect_err("Parsed successfully with an unrecognized destination option type");
2097 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
2098 pointer,
2099 must_send_icmp,
2100 action,
2101 } = error
2102 {
2103 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 16);
2104 assert!(must_send_icmp);
2105 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
2106 } else {
2107 panic!("Should have matched with UnrecognizedOption: {:?}", error);
2108 }
2109 }
2110
2111 #[test]
2112 fn test_serialize_hbh_router_alert() {
2113 let mut buffer = [0u8; 4];
2114 let option = HopByHopOption {
2115 action: ExtensionHeaderOptionAction::SkipAndContinue,
2116 mutable: false,
2117 data: HopByHopOptionData::RouterAlert { data: 0 },
2118 };
2119 <HopByHopOption<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
2120 assert_eq!(&buffer[..], &[5, 2, 0, 0]);
2121 }
2122
2123 #[test]
2124 fn test_parse_hbh_router_alert() {
2125 let context = ExtensionHeaderOptionContext::new(0);
2127 let buffer = [5, 2, 0, 0];
2128
2129 let options =
2130 Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context).unwrap();
2131 let rtralrt = options.iter().next().unwrap();
2132 assert!(!rtralrt.mutable);
2133 assert_eq!(rtralrt.action, ExtensionHeaderOptionAction::SkipAndContinue);
2134 assert_eq!(rtralrt.data, HopByHopOptionData::RouterAlert { data: 0 });
2135
2136 let context = ExtensionHeaderOptionContext::new(5);
2139 let buffer = [0xC5, 2, 0, 0];
2142
2143 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2144 .expect_err("UnrecognizedOption should have been returned");
2145 assert_eq!(
2146 error,
2147 ExtensionHeaderOptionParsingError::UnrecognizedOption {
2148 pointer: 5,
2149 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast
2150 }
2151 );
2152
2153 let result = <HopByHopOptionDataImpl as ExtensionHeaderOptionDataImpl>::parse_option(
2155 5,
2156 &buffer[1..],
2157 &mut (),
2158 false,
2159 );
2160 assert_eq!(result, ExtensionHeaderOptionDataParseResult::ErrorAt(1));
2161
2162 let context = ExtensionHeaderOptionContext::new(5);
2163 let buffer = [5, 3, 0, 0, 0];
2164
2165 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2166 .expect_err(
2167 "Parsing a malformed option with recognized kind but with wrong data should fail",
2168 );
2169 assert_eq!(error, ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer: 6 });
2170 }
2171
2172 fn trivial_hbh_options(lengths: &[Option<usize>]) -> Vec<HopByHopOption<'static>> {
2179 static ZEROES: [u8; 16] = [0u8; 16];
2180 lengths
2181 .iter()
2182 .map(|l| HopByHopOption {
2183 mutable: false,
2184 action: ExtensionHeaderOptionAction::SkipAndContinue,
2185 data: match l {
2186 Some(l) => HopByHopOptionData::Unrecognized {
2187 kind: 1,
2188 len: (*l - 2) as u8,
2189 data: &ZEROES[0..*l - 2],
2190 },
2191 None => HopByHopOptionData::RouterAlert { data: 0 },
2192 },
2193 })
2194 .collect()
2195 }
2196
2197 #[test]
2198 fn test_aligned_records_serializer() {
2199 for i in 2..12 {
2201 let options = trivial_hbh_options(&[Some(i), None]);
2202 let ser = AlignedRecordSequenceBuilder::<
2203 ExtensionHeaderOption<HopByHopOptionData<'_>>,
2204 _,
2205 >::new(2, options.iter());
2206 let mut buf = [0u8; 16];
2207 ser.serialize_into(&mut buf[0..16]);
2208 let base = (i + 1) & !1;
2209 assert_eq!(&buf[base..base + 4], &[5, 2, 0, 0]);
2211 }
2212 }
2213}