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 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 {
340 pointer: context.next_header_offset as u32,
341 must_send_icmp: false,
342 })
343 }
344 }
345 }
346}
347
348impl<'a> RecordsRawImpl<'a> for Ipv6ExtensionHeaderImpl {
349 fn parse_raw_with_context<BV: BufferView<&'a [u8]>>(
350 data: &mut BV,
351 context: &mut Self::Context,
352 ) -> Result<bool, Self::Error> {
353 let (next, skip) = match Ipv6ExtHdrType::from(context.next_header) {
354 Ipv6ExtHdrType::HopByHopOptions => {
355 if context.headers_parsed == 0 {
356 data.take_front(2)
359 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
360 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
361 } else {
362 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
364 pointer: context.next_header_offset as u32,
365 must_send_icmp: false,
366 });
367 }
368 }
369
370 Ipv6ExtHdrType::Routing | Ipv6ExtHdrType::DestinationOptions => {
371 data.take_front(2)
374 .map(|x| (x[0], (x[1] as usize) * 8 + 6))
375 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
376 }
377 Ipv6ExtHdrType::Fragment => {
378 (
380 data.take_byte_front()
381 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?,
382 7,
383 )
384 }
385 Ipv6ExtHdrType::EncapsulatingSecurityPayload => {
386 return debug_err!(
390 Err(Ipv6ExtensionHeaderParsingError::MalformedData),
391 "ESP extension header not supported"
392 );
393 }
394 Ipv6ExtHdrType::Authentication => {
395 data.take_front(2)
399 .map(|x| (x[0], (x[1] as usize + 2) * 4 - 2))
400 .ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?
401 }
402 Ipv6ExtHdrType::Other(next_header) if is_valid_next_header_upper_layer(next_header) => {
403 return Ok(false);
404 }
405
406 Ipv6ExtHdrType::Other(_) => {
407 return Err(Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader {
408 pointer: context.next_header_offset as u32,
409 must_send_icmp: false,
410 });
411 }
412 };
413 let _: &[u8] =
414 data.take_front(skip).ok_or(Ipv6ExtensionHeaderParsingError::BufferExhausted)?;
415 context.next_header = next;
416 context.next_header_offset = context.position;
417 context.position += skip;
418 context.headers_parsed += 1;
419 Ok(true)
420 }
421}
422
423#[derive(Debug)]
429pub struct HopByHopOptionsData<'a> {
430 options: Records<&'a [u8], HopByHopOptionsImpl>,
431}
432
433impl<'a> HopByHopOptionsData<'a> {
434 fn new(options: Records<&'a [u8], HopByHopOptionsImpl>) -> HopByHopOptionsData<'a> {
436 HopByHopOptionsData { options }
437 }
438
439 pub fn iter(&'a self) -> impl Iterator<Item = HopByHopOption<'a>> {
442 self.options.iter()
443 }
444}
445
446pub type HopByHopOption<'a> = ExtensionHeaderOption<HopByHopOptionData<'a>>;
448
449pub(super) type HopByHopOptionsImpl = ExtensionHeaderOptionImpl<HopByHopOptionDataImpl>;
452
453const HBH_OPTION_KIND_RTRALRT: u8 = 5;
457
458const HBH_OPTION_RTRALRT_LEN: usize = 2;
462
463#[allow(missing_docs)]
465#[derive(Debug, PartialEq, Eq, Clone)]
466pub enum HopByHopOptionData<'a> {
467 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
468 RouterAlert { data: u16 },
469}
470
471#[derive(Debug)]
473pub(super) struct HopByHopOptionDataImpl;
474
475impl ExtensionHeaderOptionDataImplLayout for HopByHopOptionDataImpl {
476 type Context = ();
477}
478
479impl ExtensionHeaderOptionDataImpl for HopByHopOptionDataImpl {
480 type OptionData<'a> = HopByHopOptionData<'a>;
481
482 fn parse_option<'a>(
483 kind: u8,
484 data: &'a [u8],
485 _context: &mut Self::Context,
486 allow_unrecognized: bool,
487 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
488 match kind {
489 HBH_OPTION_KIND_RTRALRT => {
490 if data.len() == HBH_OPTION_RTRALRT_LEN {
491 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::RouterAlert {
492 data: NetworkEndian::read_u16(data),
493 })
494 } else {
495 ExtensionHeaderOptionDataParseResult::ErrorAt(1)
498 }
499 }
500 _ => {
501 if allow_unrecognized {
502 ExtensionHeaderOptionDataParseResult::Ok(HopByHopOptionData::Unrecognized {
503 kind,
504 len: data.len() as u8,
505 data,
506 })
507 } else {
508 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
509 }
510 }
511 }
512 }
513}
514
515impl OptionLayout for HopByHopOptionsImpl {
516 type KindLenField = u8;
517 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
518}
519
520impl OptionParseLayout for HopByHopOptionsImpl {
521 type Error = OptionParseErr;
522 const END_OF_OPTIONS: Option<u8> = Some(0);
523 const NOP: Option<u8> = Some(1);
524}
525
526#[doc(hidden)]
532pub enum HopByHopOptionLayout {}
533
534impl OptionLayout for HopByHopOptionLayout {
535 type KindLenField = u8;
536 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::ValueOnly;
537}
538
539impl<'a> OptionBuilder for HopByHopOption<'a> {
540 type Layout = HopByHopOptionLayout;
541 fn serialized_len(&self) -> usize {
542 match self.data {
543 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_RTRALRT_LEN,
544 HopByHopOptionData::Unrecognized { len, .. } => len as usize,
545 }
546 }
547
548 fn option_kind(&self) -> u8 {
549 let action: u8 = self.action.into();
550 let mutable = self.mutable as u8;
551 let type_number = match self.data {
552 HopByHopOptionData::Unrecognized { kind, .. } => kind,
553 HopByHopOptionData::RouterAlert { .. } => HBH_OPTION_KIND_RTRALRT,
554 };
555 (action << 6) | (mutable << 5) | type_number
556 }
557
558 fn serialize_into(&self, mut buffer: &mut [u8]) {
559 match self.data {
560 HopByHopOptionData::Unrecognized { data, .. } => buffer.copy_from_slice(data),
561 HopByHopOptionData::RouterAlert { data } => {
562 (&mut buffer).write_obj_front(&U16::new(data)).unwrap()
565 }
566 }
567 }
568}
569
570impl<'a> AlignedOptionBuilder for HopByHopOption<'a> {
571 fn alignment_requirement(&self) -> (usize, usize) {
572 match self.data {
573 HopByHopOptionData::RouterAlert { .. } => (2, 0),
576 _ => (1, 0),
577 }
578 }
579
580 fn serialize_padding(buf: &mut [u8], length: usize) {
581 assert!(length <= buf.len());
582 assert!(length <= (u8::MAX as usize) + 2);
583
584 #[allow(clippy::comparison_chain)]
585 if length == 1 {
586 buf[0] = 0
588 } else if length > 1 {
589 buf[0] = 1;
591 buf[1] = (length - 2) as u8;
592 #[allow(clippy::needless_range_loop)]
593 for i in 2..length {
594 buf[i] = 0
595 }
596 }
597 }
598}
599
600#[derive(Debug)]
620pub struct RoutingData<'a> {
621 bytes: &'a [u8],
622}
623
624#[derive(Debug, PartialEq, Eq)]
626pub enum RoutingType {}
627
628#[derive(Debug, PartialEq, Eq)]
630pub enum RoutingTypeParseError {
631 UnsupportedType(u8),
634}
635
636impl TryFrom<u8> for RoutingType {
637 type Error = RoutingTypeParseError;
638
639 fn try_from(value: u8) -> Result<Self, Self::Error> {
640 Err(RoutingTypeParseError::UnsupportedType(value))
641 }
642}
643
644impl<'a> RoutingData<'a> {
645 pub fn routing_type(&self) -> Result<RoutingType, RoutingTypeParseError> {
647 debug_assert!(self.bytes.len() >= 6);
648 RoutingType::try_from(self.bytes[0])
649 }
650
651 pub fn segments_left(&self) -> u8 {
653 debug_assert!(self.bytes.len() >= 6);
654 self.bytes[1]
655 }
656}
657
658#[derive(Debug, Copy, Clone)]
674pub struct FragmentData {
675 bytes: [u8; 6],
676}
677
678impl FragmentData {
679 pub fn fragment_offset(&self) -> FragmentOffset {
681 FragmentOffset::new_with_msb(U16::from_bytes([self.bytes[0], self.bytes[1]]).get())
682 }
683
684 pub fn m_flag(&self) -> bool {
686 (self.bytes[1] & 0x1) == 0x01
687 }
688
689 pub fn identification(&self) -> u32 {
691 NetworkEndian::read_u32(&self.bytes[2..6])
692 }
693}
694
695#[derive(Debug)]
701pub struct DestinationOptionsData<'a> {
702 options: Records<&'a [u8], DestinationOptionsImpl>,
703}
704
705impl<'a> DestinationOptionsData<'a> {
706 fn new(options: Records<&'a [u8], DestinationOptionsImpl>) -> DestinationOptionsData<'a> {
708 DestinationOptionsData { options }
709 }
710
711 pub fn iter(&'a self) -> impl Iterator<Item = DestinationOption<'a>> {
714 self.options.iter()
715 }
716}
717
718pub type DestinationOption<'a> = ExtensionHeaderOption<DestinationOptionData<'a>>;
720
721pub(super) type DestinationOptionsImpl = ExtensionHeaderOptionImpl<DestinationOptionDataImpl>;
724
725#[allow(missing_docs)]
727#[derive(Debug)]
728pub enum DestinationOptionData<'a> {
729 Unrecognized { kind: u8, len: u8, data: &'a [u8] },
730}
731
732#[derive(Debug)]
734pub(super) struct DestinationOptionDataImpl;
735
736impl ExtensionHeaderOptionDataImplLayout for DestinationOptionDataImpl {
737 type Context = ();
738}
739
740impl ExtensionHeaderOptionDataImpl for DestinationOptionDataImpl {
741 type OptionData<'a> = DestinationOptionData<'a>;
742
743 fn parse_option<'a>(
744 kind: u8,
745 data: &'a [u8],
746 _context: &mut Self::Context,
747 allow_unrecognized: bool,
748 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>> {
749 if allow_unrecognized {
750 ExtensionHeaderOptionDataParseResult::Ok(DestinationOptionData::Unrecognized {
751 kind,
752 len: data.len() as u8,
753 data,
754 })
755 } else {
756 ExtensionHeaderOptionDataParseResult::UnrecognizedKind
757 }
758 }
759}
760
761#[derive(Debug, Clone)]
767pub(super) struct ExtensionHeaderOptionContext<C: Sized + Clone> {
768 options_parsed: usize,
770
771 position: usize,
773
774 specific_context: C,
776}
777
778impl<C: Sized + Clone + Default> ExtensionHeaderOptionContext<C> {
779 fn new(offset: usize) -> Self {
780 ExtensionHeaderOptionContext {
781 options_parsed: 0,
782 position: offset,
783 specific_context: C::default(),
784 }
785 }
786}
787
788impl<C: Sized + Clone> RecordsContext for ExtensionHeaderOptionContext<C> {}
789
790pub(super) trait ExtensionHeaderOptionDataImplLayout {
792 type Context: RecordsContext;
795}
796
797#[derive(PartialEq, Eq, Debug)]
799pub enum ExtensionHeaderOptionDataParseResult<D> {
800 Ok(D),
802
803 ErrorAt(u32),
809
810 UnrecognizedKind,
812}
813
814pub(super) trait ExtensionHeaderOptionDataImpl: ExtensionHeaderOptionDataImplLayout {
816 type OptionData<'a>: Sized;
822
823 fn parse_option<'a>(
834 kind: u8,
835 data: &'a [u8],
836 context: &mut Self::Context,
837 allow_unrecognized: bool,
838 ) -> ExtensionHeaderOptionDataParseResult<Self::OptionData<'a>>;
839}
840
841#[derive(Debug)]
848pub(super) struct ExtensionHeaderOptionImpl<O>(PhantomData<O>);
849
850impl<O> ExtensionHeaderOptionImpl<O> {
851 const PAD1: u8 = 0;
852 const PADN: u8 = 1;
853}
854
855impl<O> RecordsImplLayout for ExtensionHeaderOptionImpl<O>
856where
857 O: ExtensionHeaderOptionDataImplLayout,
858{
859 type Error = ExtensionHeaderOptionParsingError;
860 type Context = ExtensionHeaderOptionContext<O::Context>;
861}
862
863impl<O> RecordsImpl for ExtensionHeaderOptionImpl<O>
864where
865 O: ExtensionHeaderOptionDataImpl,
866{
867 type Record<'a> = ExtensionHeaderOption<O::OptionData<'a>>;
868
869 fn parse_with_context<'a, BV: BufferView<&'a [u8]>>(
870 data: &mut BV,
871 context: &mut Self::Context,
872 ) -> RecordParseResult<Self::Record<'a>, Self::Error> {
873 let kind = match data.take_byte_front() {
875 None => return Ok(ParsedRecord::Done),
876 Some(k) => k,
877 };
878
879 let action =
883 ExtensionHeaderOptionAction::try_from((kind >> 6) & 0x3).expect("Unexpected error");
884 let mutable = ((kind >> 5) & 0x1) == 0x1;
885 if kind == Self::PAD1 {
891 context.options_parsed += 1;
893 context.position += 1;
894
895 return Ok(ParsedRecord::Skipped);
896 }
897
898 let len =
899 data.take_byte_front().ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
900
901 let data = data
902 .take_front(len as usize)
903 .ok_or(ExtensionHeaderOptionParsingError::BufferExhausted)?;
904
905 if kind == Self::PADN {
907 context.options_parsed += 1;
909 context.position += 2 + (len as usize);
910
911 return Ok(ParsedRecord::Skipped);
912 }
913
914 match O::parse_option(
916 kind,
917 data,
918 &mut context.specific_context,
919 action == ExtensionHeaderOptionAction::SkipAndContinue,
920 ) {
921 ExtensionHeaderOptionDataParseResult::Ok(o) => {
922 context.options_parsed += 1;
924 context.position += 2 + (len as usize);
925
926 Ok(ParsedRecord::Parsed(ExtensionHeaderOption { action, mutable, data: o }))
927 }
928 ExtensionHeaderOptionDataParseResult::ErrorAt(offset) => {
929 Err(ExtensionHeaderOptionParsingError::ErroneousOptionField {
934 pointer: u32::try_from(context.position + offset as usize).unwrap(),
935 })
936 }
937 ExtensionHeaderOptionDataParseResult::UnrecognizedKind => {
938 match action {
940 ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
947 "Should never end up here since action was set to skip and continue"
948 ),
949 _ => Err(ExtensionHeaderOptionParsingError::UnrecognizedOption {
960 pointer: u32::try_from(context.position).unwrap(),
961 action,
962 }),
963 }
964 }
965 }
966 }
967}
968
969#[allow(missing_docs)]
971#[derive(Debug, PartialEq, Eq)]
972pub(crate) enum ExtensionHeaderOptionParsingError {
973 ErroneousOptionField { pointer: u32 },
974 UnrecognizedOption { pointer: u32, action: ExtensionHeaderOptionAction },
975 BufferExhausted,
976}
977
978impl From<Never> for ExtensionHeaderOptionParsingError {
979 fn from(err: Never) -> ExtensionHeaderOptionParsingError {
980 match err {}
981 }
982}
983
984#[derive(Debug, PartialEq, Eq, Clone, Copy)]
990pub enum ExtensionHeaderOptionAction {
991 SkipAndContinue,
994
995 DiscardPacket,
998
999 DiscardPacketSendIcmp,
1005
1006 DiscardPacketSendIcmpNoMulticast,
1012}
1013
1014impl TryFrom<u8> for ExtensionHeaderOptionAction {
1015 type Error = ();
1016
1017 fn try_from(value: u8) -> Result<Self, ()> {
1018 match value {
1019 0 => Ok(ExtensionHeaderOptionAction::SkipAndContinue),
1020 1 => Ok(ExtensionHeaderOptionAction::DiscardPacket),
1021 2 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmp),
1022 3 => Ok(ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast),
1023 _ => Err(()),
1024 }
1025 }
1026}
1027
1028impl From<ExtensionHeaderOptionAction> for u8 {
1029 fn from(a: ExtensionHeaderOptionAction) -> u8 {
1030 match a {
1031 ExtensionHeaderOptionAction::SkipAndContinue => 0,
1032 ExtensionHeaderOptionAction::DiscardPacket => 1,
1033 ExtensionHeaderOptionAction::DiscardPacketSendIcmp => 2,
1034 ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => 3,
1035 }
1036 }
1037}
1038
1039#[derive(PartialEq, Eq, Debug, Clone)]
1045pub struct ExtensionHeaderOption<O> {
1046 pub action: ExtensionHeaderOptionAction,
1048
1049 pub mutable: bool,
1055
1056 pub data: O,
1058}
1059
1060pub(super) fn is_valid_next_header_upper_layer(next_header: u8) -> bool {
1069 match Ipv6Proto::from(next_header) {
1070 Ipv6Proto::Proto(IpProto::Tcp)
1071 | Ipv6Proto::Proto(IpProto::Udp)
1072 | Ipv6Proto::Icmpv6
1073 | Ipv6Proto::NoNextHeader => true,
1074 Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => false,
1075 }
1076}
1077
1078fn ext_hdr_opt_err_to_ext_hdr_err(
1084 err: ExtensionHeaderOptionParsingError,
1085) -> Ipv6ExtensionHeaderParsingError {
1086 match err {
1087 ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer } => {
1088 Ipv6ExtensionHeaderParsingError::ErroneousHeaderField {
1089 pointer: pointer,
1090 must_send_icmp: false,
1095 }
1096 }
1097 ExtensionHeaderOptionParsingError::UnrecognizedOption { pointer, action } => {
1098 Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1099 pointer: pointer,
1100 must_send_icmp: true,
1101 action,
1102 }
1103 }
1104 ExtensionHeaderOptionParsingError::BufferExhausted => {
1105 Ipv6ExtensionHeaderParsingError::BufferExhausted
1106 }
1107 }
1108}
1109
1110#[cfg(test)]
1111mod tests {
1112 use packet::records::{AlignedRecordSequenceBuilder, RecordBuilder};
1113
1114 use crate::ip::Ipv4Proto;
1115 use crate::ipv6::IPV6_FIXED_HDR_LEN;
1116
1117 use super::*;
1118
1119 #[test]
1120 fn test_is_valid_next_header_upper_layer() {
1121 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1123 assert!(is_valid_next_header_upper_layer(IpProto::Tcp.into()));
1124
1125 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1127 assert!(!is_valid_next_header_upper_layer(Ipv4Proto::Icmp.into()));
1128 }
1129
1130 #[test]
1131 fn test_hop_by_hop_options() {
1132 let buffer = [0; 10];
1134 let mut context = ExtensionHeaderOptionContext::new(10);
1135 let options =
1136 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1137 .unwrap();
1138 assert_eq!(options.iter().count(), 0);
1139 assert_eq!(context.position, 20);
1140 assert_eq!(context.options_parsed, 10);
1141
1142 #[rustfmt::skip]
1144 let buffer = [
1145 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1149 let mut context = ExtensionHeaderOptionContext::new(1);
1150 let options =
1151 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1152 .unwrap();
1153 assert_eq!(options.iter().count(), 0);
1154 assert_eq!(context.position, 14);
1155 assert_eq!(context.options_parsed, 3);
1156
1157 #[rustfmt::skip]
1160 let buffer = [
1161 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1165 let mut context = ExtensionHeaderOptionContext::new(1);
1166 let options =
1167 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1168 .unwrap();
1169 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1170 assert_eq!(options.len(), 1);
1171 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1172 assert_eq!(context.position, 13);
1173 assert_eq!(context.options_parsed, 3);
1174 }
1175
1176 #[test]
1177 fn test_hop_by_hop_options_err() {
1178 #[rustfmt::skip]
1180 let buffer = [
1181 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1185 let mut context = ExtensionHeaderOptionContext::new(5);
1186 assert_eq!(
1187 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1188 .expect_err("Parsed successfully when we were short 2 bytes"),
1189 ExtensionHeaderOptionParsingError::BufferExhausted
1190 );
1191 assert_eq!(context.position, 8);
1192 assert_eq!(context.options_parsed, 2);
1193
1194 #[rustfmt::skip]
1196 let buffer = [
1197 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1201 let mut context = ExtensionHeaderOptionContext::new(5);
1202 assert_eq!(
1203 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1204 .expect_err("Parsed successfully when we had an unrecognized option type"),
1205 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1206 pointer: 8,
1207 action: ExtensionHeaderOptionAction::DiscardPacket,
1208 }
1209 );
1210 assert_eq!(context.position, 8);
1211 assert_eq!(context.options_parsed, 1);
1212
1213 #[rustfmt::skip]
1216 let buffer = [
1217 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1222 let mut context = ExtensionHeaderOptionContext::new(5);
1223 assert_eq!(
1224 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1225 .expect_err("Parsed successfully when we had an unrecognized option type"),
1226 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1227 pointer: 8,
1228 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1229 }
1230 );
1231 assert_eq!(context.position, 8);
1232 assert_eq!(context.options_parsed, 1);
1233
1234 #[rustfmt::skip]
1237 let buffer = [
1238 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1243 let mut context = ExtensionHeaderOptionContext::new(5);
1244 assert_eq!(
1245 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1246 .expect_err("Parsed successfully when we had an unrecognized option type"),
1247 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1248 pointer: 8,
1249 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1250 }
1251 );
1252 assert_eq!(context.position, 8);
1253 assert_eq!(context.options_parsed, 1);
1254
1255 #[rustfmt::skip]
1257 let buffer = [
1258 0xC0,
1261 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1264 let mut context = ExtensionHeaderOptionContext::new(5);
1265 assert_eq!(
1266 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1267 .expect_err("Parsed successfully when we had Pad1 with upper bits set"),
1268 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1269 pointer: 5,
1270 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1271 }
1272 );
1273 assert_eq!(context.position, 5);
1274 assert_eq!(context.options_parsed, 0);
1275
1276 #[rustfmt::skip]
1278 let buffer = [
1279 0, 0xC1, 0,
1283 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1285 let mut context = ExtensionHeaderOptionContext::new(5);
1286 assert_eq!(
1287 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1288 .expect_err("Parsed successfully when we had Pad2 with upper bits set"),
1289 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1290 pointer: 6,
1291 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1292 }
1293 );
1294 assert_eq!(context.position, 6);
1295 assert_eq!(context.options_parsed, 1);
1296
1297 #[rustfmt::skip]
1299 let buffer = [
1300 0, 1, 0, 0xC1, 8, 0, 0, 0, 0, 0, 0, 0, 0,
1305 ];
1306 let mut context = ExtensionHeaderOptionContext::new(5);
1307 assert_eq!(
1308 Records::<_, HopByHopOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1309 .expect_err("Parsed successfully when we had PadN with upper bits set"),
1310 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1311 pointer: 8,
1312 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1313 }
1314 );
1315 assert_eq!(context.position, 8);
1316 assert_eq!(context.options_parsed, 2);
1317 }
1318
1319 #[test]
1320 fn test_destination_options() {
1321 let buffer = [0; 10];
1323 let mut context = ExtensionHeaderOptionContext::new(5);
1324 let options =
1325 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1326 .unwrap();
1327 assert_eq!(options.iter().count(), 0);
1328 assert_eq!(context.position, 15);
1329 assert_eq!(context.options_parsed, 10);
1330
1331 #[rustfmt::skip]
1333 let buffer = [
1334 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, ];
1338 let mut context = ExtensionHeaderOptionContext::new(5);
1339 let options =
1340 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1341 .unwrap();
1342 assert_eq!(options.iter().count(), 0);
1343 assert_eq!(context.position, 18);
1344 assert_eq!(context.options_parsed, 3);
1345
1346 #[rustfmt::skip]
1349 let buffer = [
1350 0, 63, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1354 let mut context = ExtensionHeaderOptionContext::new(5);
1355 let options =
1356 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1357 .unwrap();
1358 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1359 assert_eq!(options.len(), 1);
1360 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1361 assert_eq!(context.position, 17);
1362 assert_eq!(context.options_parsed, 3);
1363 }
1364
1365 #[test]
1366 fn test_destination_options_err() {
1367 #[rustfmt::skip]
1369 let buffer = [
1370 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, ];
1374 let mut context = ExtensionHeaderOptionContext::new(5);
1375 assert_eq!(
1376 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1377 .expect_err("Parsed successfully when we were short 2 bytes"),
1378 ExtensionHeaderOptionParsingError::BufferExhausted
1379 );
1380 assert_eq!(context.position, 8);
1381 assert_eq!(context.options_parsed, 2);
1382
1383 #[rustfmt::skip]
1385 let buffer = [
1386 1, 1, 0, 127, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1390 let mut context = ExtensionHeaderOptionContext::new(5);
1391 assert_eq!(
1392 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1393 .expect_err("Parsed successfully when we had an unrecognized option type"),
1394 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1395 pointer: 8,
1396 action: ExtensionHeaderOptionAction::DiscardPacket,
1397 }
1398 );
1399 assert_eq!(context.position, 8);
1400 assert_eq!(context.options_parsed, 1);
1401
1402 #[rustfmt::skip]
1405 let buffer = [
1406 1, 1, 0, 191, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1411 let mut context = ExtensionHeaderOptionContext::new(5);
1412 assert_eq!(
1413 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1414 .expect_err("Parsed successfully when we had an unrecognized option type"),
1415 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1416 pointer: 8,
1417 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmp,
1418 }
1419 );
1420 assert_eq!(context.position, 8);
1421 assert_eq!(context.options_parsed, 1);
1422
1423 #[rustfmt::skip]
1426 let buffer = [
1427 1, 1, 0, 255, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
1432 let mut context = ExtensionHeaderOptionContext::new(5);
1433 assert_eq!(
1434 Records::<_, DestinationOptionsImpl>::parse_with_mut_context(&buffer[..], &mut context)
1435 .expect_err("Parsed successfully when we had an unrecognized option type"),
1436 ExtensionHeaderOptionParsingError::UnrecognizedOption {
1437 pointer: 8,
1438 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast,
1439 }
1440 );
1441 assert_eq!(context.position, 8);
1442 assert_eq!(context.options_parsed, 1);
1443 }
1444
1445 #[test]
1446 fn test_hop_by_hop_options_ext_hdr() {
1447 let context =
1450 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1451 #[rustfmt::skip]
1452 let buffer = [
1453 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1458 let ext_hdrs =
1459 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1460 .unwrap();
1461 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1462 assert_eq!(ext_hdrs.len(), 1);
1463 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1464 let options: Vec<HopByHopOption<'_>> = options.iter().collect();
1466 assert_eq!(options.len(), 1);
1467 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1468 } else {
1469 panic!("Should have matched HopByHopOptions {:?}", ext_hdrs[0]);
1470 }
1471 }
1472
1473 #[test]
1474 fn test_hop_by_hop_options_ext_hdr_err() {
1475 let context =
1479 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1480 #[rustfmt::skip]
1481 let buffer = [
1482 255, 0, 1, 4, 0, 0, 0, 0, ];
1486 let error =
1487 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1488 .expect_err("Parsed successfully when the next header was invalid");
1489 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1490 error
1491 {
1492 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1493 assert!(!must_send_icmp);
1494 } else {
1495 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1496 }
1497
1498 let context =
1500 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1501 #[rustfmt::skip]
1502 let buffer = [
1503 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1508 let error =
1509 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1510 .expect_err("Parsed successfully with an unrecognized option type");
1511 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1512 pointer,
1513 must_send_icmp,
1514 action,
1515 } = error
1516 {
1517 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1518 assert!(must_send_icmp);
1519 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1520 } else {
1521 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1522 }
1523
1524 let context =
1526 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1527 #[rustfmt::skip]
1528 let buffer = [
1529 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1534 let error =
1535 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1536 .expect_err("Parsed successfully with an unrecognized option type");
1537 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1538 pointer,
1539 must_send_icmp,
1540 action,
1541 } = error
1542 {
1543 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1544 assert!(must_send_icmp);
1545 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1546 } else {
1547 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1548 }
1549
1550 let context =
1552 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1553 #[rustfmt::skip]
1554 let buffer = [
1555 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1561 let error =
1562 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1563 .expect_err("Parsed successfully with an unrecognized option type");
1564 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1565 pointer,
1566 must_send_icmp,
1567 action,
1568 } = error
1569 {
1570 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1571 assert!(must_send_icmp);
1572 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1573 } else {
1574 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1575 }
1576
1577 let context =
1579 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1580 #[rustfmt::skip]
1581 let buffer = [
1582 IpProto::Tcp.into(), 0, 5, 3, 0, 0, 0, 0, ];
1587 let error =
1588 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1589 .expect_err(
1590 "Should fail to parse the header because one of the option is malformed",
1591 );
1592 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, .. } = error {
1593 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 3);
1594 } else {
1595 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1596 }
1597 }
1598
1599 #[test]
1600 fn test_routing_ext_hdr() {
1601 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1603 #[rustfmt::skip]
1604 let buffer = [
1605 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,
1612 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1613
1614 ];
1615 let ext_hdrs =
1616 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1617 .unwrap();
1618 let results: Vec<_> = ext_hdrs.iter().collect();
1619 assert_eq!(results.len(), 1);
1620 if let Ipv6ExtensionHeader::Routing { routing_data } = &results[0] {
1621 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1622 assert_eq!(routing_data.segments_left(), 0);
1623 } else {
1624 panic!("Should have matched with RoutingExtensionHeader");
1625 }
1626 }
1627
1628 #[test]
1629 fn test_routing_ext_hdr_err() {
1630 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1634 #[rustfmt::skip]
1635 let buffer = [
1636 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,
1643 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1644 ];
1645 let error =
1646 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1647 .expect_err("Parsed successfully when the routing type was set to 0");
1648 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1649 error
1650 {
1651 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1652 assert!(must_send_icmp);
1653 } else {
1654 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1655 }
1656
1657 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1659 #[rustfmt::skip]
1660 let buffer = [
1661 255, 4, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1668 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1669
1670 ];
1671 let error =
1672 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1673 .expect_err("Parsed successfully when the next header was invalid");
1674 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1675 error
1676 {
1677 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1678 assert!(!must_send_icmp);
1679 } else {
1680 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1681 }
1682
1683 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
1685 #[rustfmt::skip]
1686 let buffer = [
1687 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,
1694 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1695
1696 ];
1697 let error =
1698 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1699 .expect_err("Parsed successfully with an unrecognized routing type");
1700 if let Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } =
1701 error
1702 {
1703 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 2);
1705 assert!(must_send_icmp);
1706 } else {
1707 panic!("Should have matched with ErroneousHeaderField: {:?}", error);
1708 }
1709 }
1710
1711 #[test]
1712 fn test_fragment_ext_hdr() {
1713 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1715 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1716 let identification: u32 = 3266246449;
1717 #[rustfmt::skip]
1718 let buffer = [
1719 IpProto::Tcp.into(), 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1725 ((identification >> 16) & 0xFF) as u8,
1726 ((identification >> 8) & 0xFF) as u8,
1727 (identification & 0xFF) as u8,
1728 ];
1729 let ext_hdrs =
1730 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1731 .unwrap();
1732 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1733 assert_eq!(ext_hdrs.len(), 1);
1734
1735 if let Ipv6ExtensionHeader::Fragment { fragment_data } = &ext_hdrs[0] {
1736 assert_eq!(fragment_data.fragment_offset().into_raw(), 5063);
1737 assert_eq!(fragment_data.m_flag(), true);
1738 assert_eq!(fragment_data.identification(), 3266246449);
1739 } else {
1740 panic!("Should have matched Fragment: {:?}", &ext_hdrs[0]);
1741 }
1742 }
1743
1744 #[test]
1745 fn test_fragment_ext_hdr_err() {
1746 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Fragment.into());
1750 let frag_offset_res_m_flag: u16 = (5063 << 3) | 1;
1751 let identification: u32 = 3266246449;
1752 #[rustfmt::skip]
1753 let buffer = [
1754 255, 0, (frag_offset_res_m_flag >> 8) as u8, (frag_offset_res_m_flag & 0xFF) as u8, (identification >> 24) as u8,
1760 ((identification >> 16) & 0xFF) as u8,
1761 ((identification >> 8) & 0xFF) as u8,
1762 (identification & 0xFF) as u8,
1763 ];
1764 let error =
1765 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1766 .expect_err("Parsed successfully when the next header was invalid");
1767 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1768 error
1769 {
1770 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1771 assert!(!must_send_icmp);
1772 } else {
1773 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1774 }
1775 }
1776
1777 #[test]
1778 fn test_no_next_header_ext_hdr() {
1779 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6Proto::NoNextHeader.into());
1781 #[rustfmt::skip]
1782 let buffer = [0, 0, 0, 0,];
1783 let ext_hdrs =
1784 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1785 .unwrap();
1786 assert_eq!(ext_hdrs.iter().count(), 0);
1787 }
1788
1789 #[test]
1790 fn test_destination_options_ext_hdr() {
1791 let context =
1794 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1795 #[rustfmt::skip]
1796 let buffer = [
1797 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1802 let ext_hdrs =
1803 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1804 .unwrap();
1805 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1806 assert_eq!(ext_hdrs.len(), 1);
1807 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[0] {
1808 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1810 assert_eq!(options.len(), 1);
1811 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1812 } else {
1813 panic!("Should have matched DestinationOptions: {:?}", &ext_hdrs[0]);
1814 }
1815 }
1816
1817 #[test]
1818 fn test_destination_options_ext_hdr_err() {
1819 let context =
1821 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1822
1823 #[rustfmt::skip]
1825 let buffer = [
1826 255, 0, 1, 4, 0, 0, 0, 0, ];
1830 let error =
1831 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1832 .expect_err("Parsed successfully when the next header was invalid");
1833 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
1834 error
1835 {
1836 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
1837 assert!(!must_send_icmp);
1838 } else {
1839 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
1840 }
1841
1842 let context =
1844 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1845 #[rustfmt::skip]
1846 let buffer = [
1847 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 127, 6, 0, 0, 0, 0, 0, 0, ];
1852 let error =
1853 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1854 .expect_err("Parsed successfully with an unrecognized option type");
1855 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1856 pointer,
1857 must_send_icmp,
1858 action,
1859 } = error
1860 {
1861 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1862 assert!(must_send_icmp);
1863 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacket);
1864 } else {
1865 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1866 }
1867
1868 let context =
1870 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1871 #[rustfmt::skip]
1872 let buffer = [
1873 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 191, 6, 0, 0, 0, 0, 0, 0, ];
1878 let error =
1879 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1880 .expect_err("Parsed successfully with an unrecognized option type");
1881 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1882 pointer,
1883 must_send_icmp,
1884 action,
1885 } = error
1886 {
1887 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1888 assert!(must_send_icmp);
1889 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
1890 } else {
1891 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1892 }
1893
1894 let context =
1896 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::DestinationOptions.into());
1897 #[rustfmt::skip]
1898 let buffer = [
1899 IpProto::Tcp.into(), 1, 1, 4, 0, 0, 0, 0, 255, 6, 0, 0, 0, 0, 0, 0, ];
1905 let error =
1906 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1907 .expect_err("Parsed successfully with an unrecognized option type");
1908 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
1909 pointer,
1910 must_send_icmp,
1911 action,
1912 } = error
1913 {
1914 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
1915 assert!(must_send_icmp);
1916 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast);
1917 } else {
1918 panic!("Should have matched with UnrecognizedOption: {:?}", error);
1919 }
1920 }
1921
1922 #[test]
1923 fn test_multiple_ext_hdrs() {
1924 let context =
1926 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1927 #[rustfmt::skip]
1928 let buffer = [
1929 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,
1944 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1945
1946 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 63, 6, 0, 0, 0, 0, 0, 0, ];
1954 let ext_hdrs =
1955 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
1956 .unwrap();
1957
1958 let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = ext_hdrs.iter().collect();
1959 assert_eq!(ext_hdrs.len(), 3);
1960
1961 if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1963 assert_eq!(options.iter().count(), 0);
1965 } else {
1966 panic!("Should have matched HopByHopOptions: {:?}", &ext_hdrs[0]);
1967 }
1968
1969 if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1971 assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1972 assert_eq!(routing_data.segments_left(), 0);
1973 } else {
1974 panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1975 }
1976
1977 if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
1979 let options: Vec<DestinationOption<'_>> = options.iter().collect();
1981 assert_eq!(options.len(), 1);
1982 assert_eq!(options[0].action, ExtensionHeaderOptionAction::SkipAndContinue);
1983 } else {
1984 panic!("Should have matched DestinationOptions: {:?}", ext_hdrs[2]);
1985 }
1986 }
1987
1988 #[test]
1989 fn test_multiple_ext_hdrs_errs() {
1990 let context =
1994 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
1995 #[rustfmt::skip]
1996 let buffer = [
1997 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,
2012 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2013
2014 IpProto::Tcp.into(), 1, 0, 1, 0, 1, 1, 0, 1, 6, 0, 0, 0, 0, 0, 0, ];
2022 let error =
2023 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2024 .expect_err("Parsed successfully when the next header was invalid");
2025 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2026 error
2027 {
2028 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 8);
2029 assert!(!must_send_icmp);
2030 } else {
2031 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2032 }
2033
2034 let context = Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::Routing.into());
2036 #[rustfmt::skip]
2037 let buffer = [
2038 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,
2046 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2047
2048 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, ];
2063 let error =
2064 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2065 .expect_err("Parsed successfully when a hop by hop extension header was not the fist extension header");
2066 if let Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } =
2067 error
2068 {
2069 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32);
2070 assert!(!must_send_icmp);
2071 } else {
2072 panic!("Should have matched with UnrecognizedNextHeader: {:?}", error);
2073 }
2074
2075 let context =
2078 Ipv6ExtensionHeaderParsingContext::new(Ipv6ExtHdrType::HopByHopOptions.into());
2079 #[rustfmt::skip]
2080 let buffer = [
2081 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, ];
2096 let error =
2097 Records::<&[u8], Ipv6ExtensionHeaderImpl>::parse_with_context(&buffer[..], context)
2098 .expect_err("Parsed successfully with an unrecognized destination option type");
2099 if let Ipv6ExtensionHeaderParsingError::UnrecognizedOption {
2100 pointer,
2101 must_send_icmp,
2102 action,
2103 } = error
2104 {
2105 assert_eq!(pointer, IPV6_FIXED_HDR_LEN as u32 + 16);
2106 assert!(must_send_icmp);
2107 assert_eq!(action, ExtensionHeaderOptionAction::DiscardPacketSendIcmp);
2108 } else {
2109 panic!("Should have matched with UnrecognizedOption: {:?}", error);
2110 }
2111 }
2112
2113 #[test]
2114 fn test_serialize_hbh_router_alert() {
2115 let mut buffer = [0u8; 4];
2116 let option = HopByHopOption {
2117 action: ExtensionHeaderOptionAction::SkipAndContinue,
2118 mutable: false,
2119 data: HopByHopOptionData::RouterAlert { data: 0 },
2120 };
2121 <HopByHopOption<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
2122 assert_eq!(&buffer[..], &[5, 2, 0, 0]);
2123 }
2124
2125 #[test]
2126 fn test_parse_hbh_router_alert() {
2127 let context = ExtensionHeaderOptionContext::new(0);
2129 let buffer = [5, 2, 0, 0];
2130
2131 let options =
2132 Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context).unwrap();
2133 let rtralrt = options.iter().next().unwrap();
2134 assert!(!rtralrt.mutable);
2135 assert_eq!(rtralrt.action, ExtensionHeaderOptionAction::SkipAndContinue);
2136 assert_eq!(rtralrt.data, HopByHopOptionData::RouterAlert { data: 0 });
2137
2138 let context = ExtensionHeaderOptionContext::new(5);
2141 let buffer = [0xC5, 2, 0, 0];
2144
2145 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2146 .expect_err("UnrecognizedOption should have been returned");
2147 assert_eq!(
2148 error,
2149 ExtensionHeaderOptionParsingError::UnrecognizedOption {
2150 pointer: 5,
2151 action: ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast
2152 }
2153 );
2154
2155 let result = <HopByHopOptionDataImpl as ExtensionHeaderOptionDataImpl>::parse_option(
2157 5,
2158 &buffer[1..],
2159 &mut (),
2160 false,
2161 );
2162 assert_eq!(result, ExtensionHeaderOptionDataParseResult::ErrorAt(1));
2163
2164 let context = ExtensionHeaderOptionContext::new(5);
2165 let buffer = [5, 3, 0, 0, 0];
2166
2167 let error = Records::<_, HopByHopOptionsImpl>::parse_with_context(&buffer[..], context)
2168 .expect_err(
2169 "Parsing a malformed option with recognized kind but with wrong data should fail",
2170 );
2171 assert_eq!(error, ExtensionHeaderOptionParsingError::ErroneousOptionField { pointer: 6 });
2172 }
2173
2174 fn trivial_hbh_options(lengths: &[Option<usize>]) -> Vec<HopByHopOption<'static>> {
2181 static ZEROES: [u8; 16] = [0u8; 16];
2182 lengths
2183 .iter()
2184 .map(|l| HopByHopOption {
2185 mutable: false,
2186 action: ExtensionHeaderOptionAction::SkipAndContinue,
2187 data: match l {
2188 Some(l) => HopByHopOptionData::Unrecognized {
2189 kind: 1,
2190 len: (*l - 2) as u8,
2191 data: &ZEROES[0..*l - 2],
2192 },
2193 None => HopByHopOptionData::RouterAlert { data: 0 },
2194 },
2195 })
2196 .collect()
2197 }
2198
2199 #[test]
2200 fn test_aligned_records_serializer() {
2201 for i in 2..12 {
2203 let options = trivial_hbh_options(&[Some(i), None]);
2204 let ser = AlignedRecordSequenceBuilder::<
2205 ExtensionHeaderOption<HopByHopOptionData<'_>>,
2206 _,
2207 >::new(2, options.iter());
2208 let mut buf = [0u8; 16];
2209 ser.serialize_into(&mut buf[0..16]);
2210 let base = (i + 1) & !1;
2211 assert_eq!(&buf[base..base + 4], &[5, 2, 0, 0]);
2213 }
2214 }
2215}