1use core::borrow::Borrow;
8use core::fmt::Debug;
9
10use alloc::vec::Vec;
11
12use explicit::UnreachableExt;
13use net_types::ip::{GenericOverIp, Ip, IpInvariant, Ipv4, Ipv6, Mtu};
14use netstack3_base::{Counter, RngContext, Uninstantiable};
15use netstack3_filter::ForwardedPacket;
16use packet::{
17 Buf, BufferMut, EmptyBuf, FragmentedBuffer as _, InnerPacketBuilder as _, Nested,
18 PacketBuilder, PacketConstraints, ParsablePacket, SerializeError, Serializer,
19};
20use packet_formats::ip::FragmentOffset;
21use packet_formats::ipv4::options::Ipv4Option;
22use packet_formats::ipv4::{
23 Ipv4Header as _, Ipv4PacketBuilder, Ipv4PacketBuilderWithOptions, Ipv4PacketRaw,
24};
25use packet_formats::ipv6::{
26 Ipv6PacketBuilder, Ipv6PacketBuilderBeforeFragment, Ipv6PacketBuilderWithFragmentHeader,
27};
28use rand::Rng;
29
30const MAX_FRAGMENT_OFFSET: usize = ((1 << 13) - 1) * 8;
35
36pub trait FragmentationIpExt:
37 packet_formats::ip::IpExt<PacketBuilder: AsFragmentableIpPacketBuilder<Self>>
38{
39 type ForwardedFragmentBuilder: FragmentableIpPacketBuilder<Self>;
41 type FragmentationId: Copy + Debug;
43}
44
45impl FragmentationIpExt for Ipv4 {
46 type ForwardedFragmentBuilder = ForwardedIpv4PacketBuilder;
47 type FragmentationId = ();
48}
49
50impl FragmentationIpExt for Ipv6 {
51 type ForwardedFragmentBuilder = Uninstantiable;
54 type FragmentationId = u32;
55}
56
57#[derive(Debug, Eq, PartialEq, GenericOverIp)]
59#[generic_over_ip()]
60pub enum FragmentationError {
61 NotAllowed,
63 MtuTooSmall,
65 BodyTooLong,
67 SizeLimitExceeded,
69}
70
71pub trait FragmentableIpSerializer<I: FragmentationIpExt>: Serializer {
77 type Builder<'a>: FragmentableIpPacketBuilder<I>
79 where
80 Self: 'a;
81 type Body<'a>: AsRef<[u8]>
89 where
90 Self: 'a;
91
92 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError>;
95}
96
97impl<I, S, B> FragmentableIpSerializer<I> for Nested<S, B>
98where
99 I: FragmentationIpExt,
100 S: Serializer,
101 B: AsFragmentableIpPacketBuilder<I> + PacketBuilder,
102{
103 type Builder<'a>
104 = B::Builder<'a>
105 where
106 Self: 'a;
107
108 type Body<'a>
109 = Buf<Vec<u8>>
110 where
111 Self: 'a;
112
113 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError> {
114 let builder = self.outer().try_as_fragmentable()?;
115 let body = self
116 .inner()
117 .serialize_new_buf(PacketConstraints::UNCONSTRAINED, packet::new_buf_vec)
118 .map_err(|e| match e {
119 SerializeError::SizeLimitExceeded => FragmentationError::SizeLimitExceeded,
120 })?;
121 Ok((builder, body))
122 }
123}
124
125#[derive(Debug, Eq, PartialEq, Copy, Clone)]
126pub enum FragmentPosition {
127 First,
128 Middle,
129 Last,
130}
131
132pub struct HeaderSizes {
135 first: usize,
136 remaining: usize,
137}
138
139pub trait AsFragmentableIpPacketBuilder<I: FragmentationIpExt> {
141 type Builder<'a>: FragmentableIpPacketBuilder<I>
143 where
144 Self: 'a;
145
146 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError>;
149}
150
151pub trait FragmentableIpPacketBuilder<I: FragmentationIpExt> {
153 fn header_sizes(&self) -> HeaderSizes;
155
156 fn builder_at(
161 &self,
162 offset: FragmentOffset,
163 position: FragmentPosition,
164 identifier: I::FragmentationId,
165 ) -> impl PacketBuilder + '_;
166}
167
168impl<B> AsFragmentableIpPacketBuilder<Ipv4> for B
171where
172 B: InnerIpv4FragmentBuilder,
173{
174 type Builder<'a>
175 = Ipv4FragmentBuilder<'a, Self>
176 where
177 Self: 'a;
178
179 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError> {
180 can_fragment_ipv4(self.prefix())?;
181 Ok(Ipv4FragmentBuilder { builder: self })
182 }
183}
184
185trait InnerIpv4FragmentBuilder: PacketBuilder {
188 fn prefix(&self) -> &Ipv4PacketBuilder;
189 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder;
190 fn clone_for_fragment(&self, position: FragmentPosition) -> impl InnerIpv4FragmentBuilder;
191 fn header_sizes(&self) -> HeaderSizes;
192}
193
194impl InnerIpv4FragmentBuilder for Ipv4PacketBuilder {
195 fn prefix(&self) -> &Ipv4PacketBuilder {
196 self
197 }
198
199 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder {
200 self
201 }
202
203 fn clone_for_fragment(&self, _position: FragmentPosition) -> impl InnerIpv4FragmentBuilder {
204 self.clone()
205 }
206
207 fn header_sizes(&self) -> HeaderSizes {
208 let size = self.constraints().header_len();
209 HeaderSizes { first: size, remaining: size }
210 }
211}
212
213impl<'a, I> InnerIpv4FragmentBuilder for Ipv4PacketBuilderWithOptions<'a, I>
214where
215 I: Iterator<Item: Borrow<Ipv4Option<'a>>> + Clone,
216{
217 fn prefix(&self) -> &Ipv4PacketBuilder {
218 self.prefix_builder()
219 }
220
221 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder {
222 self.prefix_builder_mut()
223 }
224
225 fn clone_for_fragment(&self, position: FragmentPosition) -> impl InnerIpv4FragmentBuilder {
226 self.clone().with_fragment_options(position == FragmentPosition::First)
227 }
228
229 fn header_sizes(&self) -> HeaderSizes {
230 let first = self.constraints().header_len();
231 let remaining = self.clone().with_fragment_options(false).constraints().header_len();
232 HeaderSizes { first, remaining }
233 }
234}
235
236pub struct Ipv4FragmentBuilder<'a, B> {
237 builder: &'a B,
238}
239
240impl<'a, B> FragmentableIpPacketBuilder<Ipv4> for Ipv4FragmentBuilder<'a, B>
241where
242 B: InnerIpv4FragmentBuilder,
243{
244 fn header_sizes(&self) -> HeaderSizes {
245 self.builder.header_sizes()
246 }
247
248 fn builder_at(
249 &self,
250 offset: FragmentOffset,
251 position: FragmentPosition,
252 (): (),
253 ) -> impl PacketBuilder + '_ {
254 let mut builder = self.builder.clone_for_fragment(position);
255 set_ipv4_fragment(builder.prefix_mut(), offset, position);
256 builder
257 }
258}
259
260impl<B> AsFragmentableIpPacketBuilder<Ipv6> for B
261where
262 for<'a> &'a B: Ipv6PacketBuilderBeforeFragment,
263{
264 type Builder<'a>
265 = Ipv6FragmentBuilder<'a, Self>
266 where
267 Self: 'a;
268
269 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError> {
270 Ok(Ipv6FragmentBuilder { builder: self })
271 }
272}
273
274pub struct Ipv6FragmentBuilder<'a, B> {
275 builder: &'a B,
276}
277
278impl<'a, B> FragmentableIpPacketBuilder<Ipv6> for Ipv6FragmentBuilder<'a, B>
279where
280 &'a B: Ipv6PacketBuilderBeforeFragment,
281{
282 fn header_sizes(&self) -> HeaderSizes {
283 let header_len =
287 Ipv6PacketBuilderWithFragmentHeader::new(self.builder, FragmentOffset::ZERO, false, 0)
288 .constraints()
289 .header_len();
290 HeaderSizes { first: header_len, remaining: header_len }
291 }
292
293 fn builder_at(
294 &self,
295 offset: FragmentOffset,
296 position: FragmentPosition,
297 identifier: u32,
298 ) -> impl PacketBuilder + '_ {
299 Ipv6PacketBuilderWithFragmentHeader::new(
300 self.builder,
301 offset,
302 position != FragmentPosition::Last,
303 identifier,
304 )
305 }
306}
307
308impl<I, B> FragmentableIpSerializer<I> for ForwardedPacket<I, B>
309where
310 I: FragmentationIpExt,
311 B: BufferMut,
312{
313 type Builder<'a>
314 = I::ForwardedFragmentBuilder
315 where
316 Self: 'a;
317 type Body<'a>
318 = Buf<&'a [u8]>
319 where
320 Self: 'a;
321
322 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError> {
323 #[derive(GenericOverIp)]
324 #[generic_over_ip(I, Ip)]
325 struct Out<I: FragmentationIpExt>(I::ForwardedFragmentBuilder);
326 I::map_ip::<_, Result<(Out<I>, IpInvariant<Buf<&[u8]>>), FragmentationError>>(
327 self,
328 |forwarded| {
329 let mut buffer = forwarded.buffer().as_ref();
333 let packet = Ipv4PacketRaw::parse(&mut buffer, ())
334 .expect("ForwardedPacket must be parseable");
335 let builder = packet.builder();
336 can_fragment_ipv4(&builder)?;
337 let raw_options_bytes = packet
338 .options()
339 .as_ref()
340 .complete()
341 .expect("unexpected incomplete IP header")
342 .bytes();
343
344 let mut raw_options = Buf::new(
345 [0u8; packet_formats::ipv4::MAX_OPTIONS_LEN],
346 ..raw_options_bytes.len(),
347 );
348 raw_options.as_mut().copy_from_slice(raw_options_bytes);
349 let body = Buf::new(
350 packet.into_body().complete().expect("unexpected incomplete IP body"),
351 ..,
352 );
353 Ok((Out(ForwardedIpv4PacketBuilder { builder, raw_options }), IpInvariant(body)))
354 },
355 |_forwarded| Err(FragmentationError::NotAllowed),
356 )
357 .map(|(Out(builder), IpInvariant(body))| (builder, body))
358 }
359}
360
361pub struct ForwardedIpv4PacketBuilder {
362 builder: Ipv4PacketBuilder,
363 raw_options: Buf<[u8; packet_formats::ipv4::MAX_OPTIONS_LEN]>,
364}
365
366impl FragmentableIpPacketBuilder<Ipv4> for ForwardedIpv4PacketBuilder {
367 fn header_sizes(&self) -> HeaderSizes {
368 let Self { builder, raw_options } = self;
369 if raw_options.is_empty() {
370 builder.header_sizes()
371 } else {
372 let options = packet_formats::ipv4::Options::parse(raw_options.as_ref())
373 .expect("must hold valid options");
374 Ipv4PacketBuilderWithOptions::new_with_records_iter(builder.clone(), options.iter())
375 .header_sizes()
376 }
377 }
378
379 fn builder_at(
380 &self,
381 offset: FragmentOffset,
382 position: FragmentPosition,
383 (): (),
384 ) -> impl PacketBuilder + '_ {
385 let Self { builder, raw_options } = self;
386 let mut builder = builder.clone();
387 set_ipv4_fragment(&mut builder, offset, position);
388 let options = packet_formats::ipv4::Options::parse(raw_options.as_ref())
389 .expect("must hold valid options");
390 Ipv4PacketBuilderWithOptions::new_with_records_iter(builder.clone(), options.into_iter())
391 .with_fragment_options(position == FragmentPosition::First)
392 }
393}
394
395impl<I: FragmentationIpExt> FragmentableIpPacketBuilder<I> for Uninstantiable {
396 fn header_sizes(&self) -> HeaderSizes {
397 self.uninstantiable_unreachable()
398 }
399
400 fn builder_at(
401 &self,
402 _offset: FragmentOffset,
403 _position: FragmentPosition,
404 _identifier: I::FragmentationId,
405 ) -> impl PacketBuilder + '_ {
406 self.uninstantiable_unreachable::<Ipv6PacketBuilder>()
407 }
408}
409
410pub(crate) trait FragmentationIdGenContext {
415 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId;
416}
417
418#[derive(GenericOverIp)]
419#[generic_over_ip(I, Ip)]
420struct WrapFragmentationId<I: FragmentationIpExt>(I::FragmentationId);
421
422impl<BC> FragmentationIdGenContext for BC
423where
424 BC: RngContext,
425{
426 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId {
427 let WrapFragmentationId(identifier) = I::map_ip_out(
428 self,
429 |_| WrapFragmentationId(()),
430 |rng| {
431 WrapFragmentationId(rng.rng().gen_range(1..=u32::MAX))
439 },
440 );
441 identifier
442 }
443}
444
445pub(crate) struct IpFragmenter<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I> + 'a> {
446 builder: S::Builder<'a>,
447 body: S::Body<'a>,
448 consumed: usize,
449 max_fragment_body_first: usize,
450 max_fragment_body_remaining: usize,
451 identifier: I::FragmentationId,
452}
453
454pub trait Capture<'a, 'b> {}
458impl<'a, 'b, O> Capture<'a, 'b> for O
459where
460 O: 'b,
461 'a: 'b,
462{
463}
464
465fn maximum_fragment_body_with_header_and_mtu(
471 mtu: Mtu,
472 header: usize,
473) -> Result<usize, FragmentationError> {
474 let v = usize::from(mtu).checked_sub(header).ok_or(FragmentationError::MtuTooSmall)?;
475 let v = v & !0x07usize;
478
479 if v == 0 {
480 return Err(FragmentationError::MtuTooSmall);
483 }
484 Ok(v)
485}
486
487impl<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I>> IpFragmenter<'a, I, S> {
488 pub(crate) fn new<C: FragmentationIdGenContext>(
491 id_ctx: &mut C,
492 serializer: &'a S,
493 mtu: Mtu,
494 ) -> Result<Self, FragmentationError> {
495 let (builder, body) = serializer.builder_and_body()?;
496 let HeaderSizes { first, remaining } = builder.header_sizes();
497 let max_fragment_body_first = maximum_fragment_body_with_header_and_mtu(mtu, first)?;
498 let max_fragment_body_remaining =
499 maximum_fragment_body_with_header_and_mtu(mtu, remaining)?;
500
501 if body.as_ref().len() > MAX_FRAGMENT_OFFSET + max_fragment_body_remaining {
502 return Err(FragmentationError::BodyTooLong);
503 }
504
505 let identifier = id_ctx.generate_id::<I>();
506
507 Ok(Self {
508 builder,
509 body,
510 consumed: 0,
511 max_fragment_body_first,
512 max_fragment_body_remaining,
513 identifier,
514 })
515 }
516
517 pub(crate) fn next(
526 &mut self,
527 ) -> Option<(impl Serializer<Buffer = EmptyBuf> + Capture<'a, '_>, bool)> {
528 let Self {
529 builder,
530 body,
531 consumed,
532 max_fragment_body_first,
533 max_fragment_body_remaining,
534 identifier,
535 } = self;
536 let body = &AsRef::as_ref(body)[*consumed..];
537 if body.is_empty() {
538 return None;
539 }
540 let first = *consumed == 0;
541 let max_fragment_body =
542 if first { max_fragment_body_first } else { max_fragment_body_remaining };
543 let take = body.len().min(*max_fragment_body);
544 let last = take == body.len();
545 let position = match (first, last) {
546 (true, true) => {
547 panic!("unnecessary fragmentation");
548 }
549 (true, false) => FragmentPosition::First,
550 (false, false) => FragmentPosition::Middle,
551 (false, true) => FragmentPosition::Last,
552 };
553 let fragment_offset = u16::try_from(*consumed).expect("fragment offset too large");
556 let fragment_offset =
560 FragmentOffset::new_with_bytes(fragment_offset).expect("invalid offset");
561 let fragment_builder = builder.builder_at(fragment_offset, position, *identifier);
562 let end = *consumed + take;
563 let has_more = body.len() > take;
564 let fragment_body = &body[..take];
565 *consumed = end;
566 Some((fragment_body.into_serializer().encapsulate(fragment_builder), has_more))
567 }
568}
569
570fn can_fragment_ipv4(builder: &Ipv4PacketBuilder) -> Result<(), FragmentationError> {
571 if builder.read_df_flag() {
572 return Err(FragmentationError::NotAllowed);
573 }
574 Ok(())
575}
576
577fn set_ipv4_fragment(
578 builder: &mut Ipv4PacketBuilder,
579 offset: FragmentOffset,
580 position: FragmentPosition,
581) {
582 builder.mf_flag(position != FragmentPosition::Last);
583 builder.fragment_offset(offset);
584}
585
586#[derive(Default, Debug)]
588#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq))]
589pub struct FragmentationCounters<C = Counter> {
590 pub fragmentation_required: C,
592 pub fragments: C,
594 pub error_not_allowed: C,
596 pub error_mtu_too_small: C,
598 pub error_body_too_long: C,
600 pub error_inner_size_limit_exceeded: C,
602 pub error_fragmented_serializer: C,
605}
606
607impl FragmentationCounters {
608 pub(crate) fn error_counter(&self, error: &FragmentationError) -> &Counter {
609 match error {
610 FragmentationError::NotAllowed => &self.error_not_allowed,
611 FragmentationError::MtuTooSmall => &self.error_mtu_too_small,
612 FragmentationError::BodyTooLong => &self.error_body_too_long,
613 FragmentationError::SizeLimitExceeded => &self.error_inner_size_limit_exceeded,
614 }
615 }
616}
617
618#[cfg(any(test, feature = "testutils"))]
619impl From<&FragmentationCounters> for FragmentationCounters<u64> {
620 fn from(counters: &FragmentationCounters) -> FragmentationCounters<u64> {
621 let FragmentationCounters {
622 fragmentation_required,
623 fragments,
624 error_not_allowed,
625 error_mtu_too_small,
626 error_body_too_long,
627 error_inner_size_limit_exceeded,
628 error_fragmented_serializer,
629 } = counters;
630 FragmentationCounters {
631 fragmentation_required: fragmentation_required.get(),
632 fragments: fragments.get(),
633 error_not_allowed: error_not_allowed.get(),
634 error_mtu_too_small: error_mtu_too_small.get(),
635 error_body_too_long: error_body_too_long.get(),
636 error_inner_size_limit_exceeded: error_inner_size_limit_exceeded.get(),
637 error_fragmented_serializer: error_fragmented_serializer.get(),
638 }
639 }
640}
641
642#[cfg(test)]
643mod tests {
644 use super::*;
645
646 use assert_matches::assert_matches;
647 use net_types::Witness as _;
648 use netstack3_base::testutil::{TEST_ADDRS_V4, TEST_ADDRS_V6};
649 use packet::{Buffer, BufferView, GrowBuffer};
650 use packet_formats::ip::IpProto;
651 use packet_formats::ipv4::Ipv4Packet;
652 use packet_formats::ipv6::ext_hdrs::Ipv6ExtensionHeaderData;
653 use packet_formats::ipv6::{Ipv6Header, Ipv6Packet};
654 use test_case::test_case;
655
656 const TEST_MTU: Mtu = Ipv6::MINIMUM_LINK_MTU;
657
658 fn gen_body(len: usize) -> Vec<u8> {
659 (0u8..=251).cycle().take(len).collect::<Vec<u8>>()
662 }
663
664 impl<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I>> IpFragmenter<'a, I, S> {
665 fn next_serialized(&mut self) -> Buf<Vec<u8>> {
666 self.next()
667 .expect("no more fragments")
668 .0
669 .serialize_vec_outer()
670 .map_err(|(err, _serializer)| err)
671 .unwrap()
672 .unwrap_b()
673 }
674 }
675
676 trait FragmentationTestEnv<I: FragmentationIpExt> {
677 fn new_serializer<'a>(
678 &self,
679 body: &'a [u8],
680 ) -> impl FragmentableIpSerializer<I, Buffer: Buffer> + 'a;
681 fn check_fragment(
682 &self,
683 fragment: &mut Buf<Vec<u8>>,
684 position: FragmentPosition,
685 offset: usize,
686 );
687 }
688
689 #[derive(Default)]
690 struct Ipv4TestEnv {
691 dont_frag: bool,
692 }
693
694 impl Ipv4TestEnv {
695 const fn dont_frag() -> Self {
696 Self { dont_frag: true }
697 }
698 }
699
700 const IPV4_ID: u16 = 0x1234;
701 fn new_ipv4_packet_builder(dont_frag: bool) -> Ipv4PacketBuilder {
702 let mut builder = Ipv4PacketBuilder::new(
703 TEST_ADDRS_V4.local_ip,
704 TEST_ADDRS_V4.remote_ip,
705 1,
706 IpProto::Udp.into(),
707 );
708 builder.id(IPV4_ID);
709 builder.df_flag(dont_frag);
710 builder
711 }
712
713 fn parse_and_check_ipv4_packet(
714 fragment: &mut Buf<Vec<u8>>,
715 position: FragmentPosition,
716 offset: usize,
717 ) -> Ipv4Packet<&[u8]> {
718 let packet = Ipv4Packet::parse(fragment.buffer_view(), ()).expect("parse fragment");
719 assert_eq!(packet.src_ip(), TEST_ADDRS_V4.local_ip.get());
720 assert_eq!(packet.dst_ip(), TEST_ADDRS_V4.remote_ip.get());
721 assert_eq!(packet.ttl(), 1);
722 assert_eq!(packet.id(), IPV4_ID);
723 assert_eq!(packet.proto(), IpProto::Udp.into());
724 assert_eq!(packet.mf_flag(), position != FragmentPosition::Last);
725 assert_eq!(usize::from(packet.fragment_offset().into_bytes()), offset);
726 packet
727 }
728
729 impl FragmentationTestEnv<Ipv4> for Ipv4TestEnv {
730 fn new_serializer<'a>(
731 &self,
732 body: &'a [u8],
733 ) -> impl FragmentableIpSerializer<Ipv4, Buffer: Buffer> + 'a {
734 let Self { dont_frag } = self;
735 body.into_serializer().encapsulate(new_ipv4_packet_builder(*dont_frag))
736 }
737
738 fn check_fragment(
739 &self,
740 fragment: &mut Buf<Vec<u8>>,
741 position: FragmentPosition,
742 offset: usize,
743 ) {
744 let _ = parse_and_check_ipv4_packet(fragment, position, offset);
745 }
746 }
747
748 #[derive(Default)]
749 struct Ipv4WithOptionsTestEnv(Ipv4TestEnv);
750
751 const FAKE_OPTION_COPIED_KIND: u8 = 255;
753 const FAKE_OPTION_COPIED: [u8; 1] = [255];
754 const FAKE_OPTION_NOT_COPIED_KIND: u8 = 127;
755 const FAKE_OPTION_NOT_COPIED: [u8; 1] = [127];
756
757 impl FragmentationTestEnv<Ipv4> for Ipv4WithOptionsTestEnv {
758 fn new_serializer<'a>(
759 &self,
760 body: &'a [u8],
761 ) -> impl FragmentableIpSerializer<Ipv4, Buffer: Buffer> + 'a {
762 let Self(Ipv4TestEnv { dont_frag }) = self;
763 body.into_serializer().encapsulate(
764 Ipv4PacketBuilderWithOptions::new(
765 new_ipv4_packet_builder(*dont_frag),
766 [
767 Ipv4Option::Unrecognized {
768 kind: FAKE_OPTION_COPIED_KIND,
769 data: &FAKE_OPTION_COPIED[..],
770 },
771 Ipv4Option::Unrecognized {
772 kind: FAKE_OPTION_NOT_COPIED_KIND,
773 data: &FAKE_OPTION_NOT_COPIED[..],
774 },
775 ],
776 )
777 .unwrap(),
778 )
779 }
780
781 fn check_fragment(
782 &self,
783 fragment: &mut Buf<Vec<u8>>,
784 position: FragmentPosition,
785 offset: usize,
786 ) {
787 let packet = parse_and_check_ipv4_packet(fragment, position, offset);
788 let (copied, not_copied) = packet.iter_options().fold(
789 (false, false),
790 |(mut copied, mut not_copied), option| {
791 let (kind, data) = assert_matches!(option,
792 Ipv4Option::Unrecognized{ kind, data } => (kind, data)
793 );
794 assert_eq!(data.len(), 1);
795 assert_eq!(data[0], kind);
796 let seen = match kind {
797 FAKE_OPTION_COPIED_KIND => &mut copied,
798 FAKE_OPTION_NOT_COPIED_KIND => &mut not_copied,
799 k => panic!("unexpected option {k}"),
800 };
801 assert_eq!(core::mem::replace(seen, true), false);
802 (copied, not_copied)
803 },
804 );
805 assert_eq!(copied, true, "must be copied on all fragments {position:?}");
806 assert_eq!(
807 not_copied,
808 position == FragmentPosition::First,
809 "must only be in first fragment {position:?}"
810 );
811 }
812 }
813
814 struct ForwardingTestEnv<E>(E);
815 impl<I: FragmentationIpExt, E: FragmentationTestEnv<I>> FragmentationTestEnv<I>
816 for ForwardingTestEnv<E>
817 {
818 fn new_serializer<'a>(
819 &self,
820 body: &'a [u8],
821 ) -> impl FragmentableIpSerializer<I, Buffer: Buffer> + 'a {
822 use packet_formats::ip::IpPacket as _;
823 let Self(inner) = self;
824 let mut buffer = inner
825 .new_serializer(body)
826 .serialize_outer(packet::NoReuseBufferProvider(packet::new_buf_vec))
827 .map_err(|(err, _)| err)
828 .unwrap();
829 let packet =
830 <I::Packet<_> as ParsablePacket<_, _>>::parse(buffer.buffer_view(), ()).unwrap();
831 let src_addr = packet.src_ip();
832 let dst_addr = packet.dst_ip();
833 let proto = packet.proto();
834 let meta = packet.parse_metadata();
835 drop(packet);
836 ForwardedPacket::new(src_addr, dst_addr, proto, meta, buffer)
837 }
838 fn check_fragment(
839 &self,
840 fragment: &mut Buf<Vec<u8>>,
841 position: FragmentPosition,
842 offset: usize,
843 ) {
844 let Self(inner) = self;
845 inner.check_fragment(fragment, position, offset)
846 }
847 }
848
849 struct Ipv6TestEnv;
850
851 const IPV6_ID: u32 = 0x1234ABCD;
852
853 impl FragmentationTestEnv<Ipv6> for Ipv6TestEnv {
854 fn new_serializer<'a>(
855 &self,
856 body: &'a [u8],
857 ) -> impl FragmentableIpSerializer<Ipv6, Buffer: Buffer> + 'a {
858 body.into_serializer().encapsulate(Ipv6PacketBuilder::new(
859 TEST_ADDRS_V6.local_ip,
860 TEST_ADDRS_V6.remote_ip,
861 1,
862 IpProto::Udp.into(),
863 ))
864 }
865
866 fn check_fragment(
867 &self,
868 fragment: &mut Buf<Vec<u8>>,
869 position: FragmentPosition,
870 offset: usize,
871 ) {
872 let packet = Ipv6Packet::parse(fragment.buffer_view(), ()).unwrap();
873 assert_eq!(packet.src_ip(), TEST_ADDRS_V6.local_ip.get());
874 assert_eq!(packet.dst_ip(), TEST_ADDRS_V6.remote_ip.get());
875 assert_eq!(packet.hop_limit(), 1);
876 assert_eq!(packet.proto(), IpProto::Udp.into());
877 let fragment = packet
878 .iter_extension_hdrs()
879 .find_map(|h| match h.into_data() {
880 Ipv6ExtensionHeaderData::Fragment { fragment_data } => Some(fragment_data),
881 _ => None,
882 })
883 .expect("no fragment header");
884 assert_eq!(fragment.identification(), IPV6_ID);
885 assert_eq!(usize::from(fragment.fragment_offset().into_bytes()), offset);
886 assert_eq!(fragment.m_flag(), position != FragmentPosition::Last);
887 }
888 }
889
890 struct FixedIdContext;
891 impl FragmentationIdGenContext for FixedIdContext {
892 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId {
893 let WrapFragmentationId(id) =
894 I::map_ip_out((), |()| WrapFragmentationId(()), |()| WrapFragmentationId(IPV6_ID));
895 id
896 }
897 }
898
899 #[test_case::test_matrix(
900 [
901 Ipv4TestEnv::default(),
902 Ipv4WithOptionsTestEnv::default(),
903 ForwardingTestEnv(Ipv4TestEnv::default()),
904 ForwardingTestEnv(Ipv4WithOptionsTestEnv::default()),
905 Ipv6TestEnv,
906 ],
907 0..=2
908 )]
909 fn fragment<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(
910 env: E,
911 middle_fragments: usize,
912 ) {
913 let full_body = gen_body(usize::from(TEST_MTU) * (1 + middle_fragments));
918 let mut body_view = Buf::new(&full_body[..], ..);
919 let serializer = env.new_serializer(&full_body[..]);
920 let mut fragmenter = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU)
921 .expect("create fragmenter");
922
923 let mut frag = fragmenter.next_serialized();
924 env.check_fragment(&mut frag, FragmentPosition::First, body_view.prefix_len());
925 assert_eq!(
926 frag.as_ref(),
927 body_view.buffer_view().take_front(fragmenter.max_fragment_body_first).unwrap()
928 );
929
930 for _ in 0..middle_fragments {
931 let mut frag = fragmenter.next_serialized();
932 env.check_fragment(&mut frag, FragmentPosition::Middle, body_view.prefix_len());
933 assert_eq!(
934 frag.as_ref(),
935 body_view.buffer_view().take_front(fragmenter.max_fragment_body_remaining).unwrap()
936 );
937 }
938
939 let mut frag = fragmenter.next_serialized();
940 env.check_fragment(&mut frag, FragmentPosition::Last, body_view.prefix_len());
941 assert_eq!(frag.as_ref(), body_view.buffer_view().into_rest());
942
943 assert!(fragmenter.next().is_none());
945 }
946
947 #[test_case(Ipv4TestEnv::dont_frag())]
948 #[test_case(Ipv4WithOptionsTestEnv(Ipv4TestEnv::dont_frag()))]
949 #[test_case(ForwardingTestEnv(Ipv4TestEnv::dont_frag()))]
950 #[test_case(ForwardingTestEnv(Ipv6TestEnv))]
951 fn not_allowed<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
952 let body = gen_body(usize::from(TEST_MTU));
953 let serializer = env.new_serializer(&body[..]);
954 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU).map(|_| ());
955 assert_eq!(result, Err(FragmentationError::NotAllowed))
956 }
957
958 #[test_case(Ipv4TestEnv::default())]
959 #[test_case(Ipv4WithOptionsTestEnv::default())]
960 #[test_case(ForwardingTestEnv(Ipv4TestEnv::default()))]
961 #[test_case(Ipv6TestEnv)]
962 fn mtu_too_small<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
963 let body = gen_body(usize::from(TEST_MTU));
964 let serializer = env.new_serializer(&body[..]);
965 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, Mtu::new(10)).map(|_| ());
966 assert_eq!(result, Err(FragmentationError::MtuTooSmall));
967 }
968
969 #[test_case(Ipv4TestEnv::default())]
970 #[test_case(Ipv4WithOptionsTestEnv::default())]
971 #[test_case(Ipv6TestEnv)]
972 fn body_too_long<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
973 let body = gen_body(MAX_FRAGMENT_OFFSET + usize::from(TEST_MTU));
974 let serializer = env.new_serializer(&body[..]);
975 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU).map(|_| ());
976 assert_eq!(result, Err(FragmentationError::BodyTooLong));
977 }
978}