1use core::borrow::Borrow;
8use core::fmt::Debug;
9
10use alloc::vec::Vec;
11
12use net_types::ip::{GenericOverIp, Ip, IpInvariant, Ipv4, Ipv6, Mtu};
13use netstack3_base::{Counter, NetworkSerializationContext, NetworkSerializer, RngContext};
14use netstack3_filter::ForwardedPacket;
15use packet::{
16 Buf, BufferMut, EmptyBuf, FragmentedBuffer as _, InnerPacketBuilder as _,
17 NestablePacketBuilder, Nested, PacketBuilder, PacketConstraints, ParsablePacket,
18 SerializeError,
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::ext_hdrs::IPV6_FRAGMENT_EXT_HDR_LEN;
26use packet_formats::ipv6::{
27 Ipv6Packet, Ipv6PacketBuilderBeforeFragment, Ipv6PacketBuilderWithFragmentHeader,
28 Ipv6PerFragmentHeaderBuilder,
29};
30use rand::RngExt as _;
31
32const MAX_FRAGMENT_OFFSET: usize = ((1 << 13) - 1) * 8;
37
38pub trait FragmentationIpExt:
39 packet_formats::ip::IpExt<
40 PacketBuilder<NetworkSerializationContext>: AsFragmentableIpPacketBuilder<Self>,
41 >
42{
43 type ForwardedFragmentBuilder: FragmentableIpPacketBuilder<Self>;
45 type FragmentationId: Copy + Debug;
47}
48
49impl FragmentationIpExt for Ipv4 {
50 type ForwardedFragmentBuilder = ForwardedIpv4PacketBuilder;
51 type FragmentationId = ();
52}
53
54impl FragmentationIpExt for Ipv6 {
55 type ForwardedFragmentBuilder = ForwardedIpv6PacketBuilder;
56 type FragmentationId = u32;
57}
58
59#[derive(Debug, Eq, PartialEq, GenericOverIp)]
61#[generic_over_ip()]
62pub enum FragmentationError {
63 NotAllowed,
65 MtuTooSmall,
67 BodyTooLong,
69 SizeLimitExceeded,
71}
72
73pub trait FragmentableIpSerializer<I: FragmentationIpExt>: NetworkSerializer {
79 type Builder<'a>: FragmentableIpPacketBuilder<I>
81 where
82 Self: 'a;
83 type Body<'a>: AsRef<[u8]>
91 where
92 Self: 'a;
93
94 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError>;
97}
98
99impl<I, S, B> FragmentableIpSerializer<I> for Nested<S, B>
100where
101 I: FragmentationIpExt,
102 S: NetworkSerializer,
103 B: AsFragmentableIpPacketBuilder<I> + PacketBuilder<NetworkSerializationContext>,
104{
105 type Builder<'a>
106 = B::Builder<'a>
107 where
108 Self: 'a;
109
110 type Body<'a>
111 = Buf<Vec<u8>>
112 where
113 Self: 'a;
114
115 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError> {
116 let builder = self.outer().try_as_fragmentable()?;
117 let body = self
118 .inner()
119 .serialize_new_buf(
120 &mut NetworkSerializationContext::default(),
121 PacketConstraints::UNCONSTRAINED,
122 packet::new_buf_vec,
123 )
124 .map_err(|e| match e {
125 SerializeError::SizeLimitExceeded => FragmentationError::SizeLimitExceeded,
126 })?;
127 Ok((builder, body))
128 }
129}
130
131#[derive(Debug, Eq, PartialEq, Copy, Clone)]
132pub enum FragmentPosition {
133 First,
134 Middle,
135 Last,
136}
137
138pub struct HeaderSizes {
141 first: usize,
142 remaining: usize,
143}
144
145pub trait AsFragmentableIpPacketBuilder<I: FragmentationIpExt> {
147 type Builder<'a>: FragmentableIpPacketBuilder<I>
149 where
150 Self: 'a;
151
152 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError>;
155}
156
157pub trait FragmentableIpPacketBuilder<I: FragmentationIpExt> {
159 fn header_sizes(&self) -> HeaderSizes;
161
162 fn builder_at(
167 &self,
168 offset: FragmentOffset,
169 position: FragmentPosition,
170 identifier: I::FragmentationId,
171 ) -> impl PacketBuilder<NetworkSerializationContext> + '_;
172}
173
174impl<B> AsFragmentableIpPacketBuilder<Ipv4> for B
177where
178 B: InnerIpv4FragmentBuilder,
179{
180 type Builder<'a>
181 = Ipv4FragmentBuilder<'a, Self>
182 where
183 Self: 'a;
184
185 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError> {
186 can_fragment_ipv4(self.prefix())?;
187 Ok(Ipv4FragmentBuilder { builder: self })
188 }
189}
190
191trait InnerIpv4FragmentBuilder: PacketBuilder<NetworkSerializationContext> {
194 fn prefix(&self) -> &Ipv4PacketBuilder;
195 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder;
196 fn clone_for_fragment(&self, position: FragmentPosition) -> impl InnerIpv4FragmentBuilder;
197 fn header_sizes(&self) -> HeaderSizes;
198}
199
200impl InnerIpv4FragmentBuilder for Ipv4PacketBuilder {
201 fn prefix(&self) -> &Ipv4PacketBuilder {
202 self
203 }
204
205 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder {
206 self
207 }
208
209 fn clone_for_fragment(&self, _position: FragmentPosition) -> impl InnerIpv4FragmentBuilder {
210 self.clone()
211 }
212
213 fn header_sizes(&self) -> HeaderSizes {
214 let size = self.constraints().header_len();
215 HeaderSizes { first: size, remaining: size }
216 }
217}
218
219impl<'a, I> InnerIpv4FragmentBuilder for Ipv4PacketBuilderWithOptions<'a, I>
220where
221 I: Iterator<Item: Borrow<Ipv4Option<'a>>> + Clone,
222{
223 fn prefix(&self) -> &Ipv4PacketBuilder {
224 self.prefix_builder()
225 }
226
227 fn prefix_mut(&mut self) -> &mut Ipv4PacketBuilder {
228 self.prefix_builder_mut()
229 }
230
231 fn clone_for_fragment(&self, position: FragmentPosition) -> impl InnerIpv4FragmentBuilder {
232 self.clone().with_fragment_options(position == FragmentPosition::First)
233 }
234
235 fn header_sizes(&self) -> HeaderSizes {
236 let first = self.constraints().header_len();
237 let remaining = self.clone().with_fragment_options(false).constraints().header_len();
238 HeaderSizes { first, remaining }
239 }
240}
241
242pub struct Ipv4FragmentBuilder<'a, B> {
243 builder: &'a B,
244}
245
246impl<'a, B> FragmentableIpPacketBuilder<Ipv4> for Ipv4FragmentBuilder<'a, B>
247where
248 B: InnerIpv4FragmentBuilder,
249{
250 fn header_sizes(&self) -> HeaderSizes {
251 self.builder.header_sizes()
252 }
253
254 fn builder_at(
255 &self,
256 offset: FragmentOffset,
257 position: FragmentPosition,
258 (): (),
259 ) -> impl PacketBuilder<NetworkSerializationContext> + '_ {
260 let mut builder = self.builder.clone_for_fragment(position);
261 set_ipv4_fragment(builder.prefix_mut(), offset, position);
262 builder
263 }
264}
265
266impl<B> AsFragmentableIpPacketBuilder<Ipv6> for B
267where
268 for<'a> &'a B: Ipv6PacketBuilderBeforeFragment,
269{
270 type Builder<'a>
271 = Ipv6FragmentBuilder<'a, Self>
272 where
273 Self: 'a;
274
275 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError> {
276 Ok(Ipv6FragmentBuilder { builder: self })
277 }
278}
279
280pub struct Ipv6FragmentBuilder<'a, B> {
281 builder: &'a B,
282}
283
284impl<'a, B> FragmentableIpPacketBuilder<Ipv6> for Ipv6FragmentBuilder<'a, B>
285where
286 &'a B: Ipv6PacketBuilderBeforeFragment,
287{
288 fn header_sizes(&self) -> HeaderSizes {
289 let header_len =
293 Ipv6PacketBuilderWithFragmentHeader::new(self.builder, FragmentOffset::ZERO, false, 0)
294 .constraints()
295 .header_len();
296 HeaderSizes { first: header_len, remaining: header_len }
297 }
298
299 fn builder_at(
300 &self,
301 offset: FragmentOffset,
302 position: FragmentPosition,
303 identifier: u32,
304 ) -> impl PacketBuilder<NetworkSerializationContext> + '_ {
305 Ipv6PacketBuilderWithFragmentHeader::new(
306 self.builder,
307 offset,
308 position != FragmentPosition::Last,
309 identifier,
310 )
311 }
312}
313
314impl<I, B> FragmentableIpSerializer<I> for ForwardedPacket<I, B>
315where
316 I: FragmentationIpExt,
317 B: BufferMut + NetworkSerializer,
318{
319 type Builder<'a>
320 = I::ForwardedFragmentBuilder
321 where
322 Self: 'a;
323 type Body<'a>
324 = Buf<&'a [u8]>
325 where
326 Self: 'a;
327
328 fn builder_and_body(&self) -> Result<(Self::Builder<'_>, Self::Body<'_>), FragmentationError> {
329 #[derive(GenericOverIp)]
330 #[generic_over_ip(I, Ip)]
331 struct Out<I: FragmentationIpExt>(I::ForwardedFragmentBuilder);
332 I::map_ip::<_, Result<(Out<I>, IpInvariant<Buf<&[u8]>>), FragmentationError>>(
333 self,
334 |forwarded| {
335 let mut buffer = forwarded.buffer().as_ref();
339 let packet = Ipv4PacketRaw::parse(&mut buffer, ())
340 .expect("ForwardedPacket must be parseable");
341 let builder = packet.builder();
342 can_fragment_ipv4(&builder)?;
343 let raw_options_bytes = packet
344 .options()
345 .as_ref()
346 .complete()
347 .expect("unexpected incomplete IP header")
348 .bytes();
349
350 let mut raw_options = Buf::new(
351 [0u8; packet_formats::ipv4::MAX_OPTIONS_LEN],
352 ..raw_options_bytes.len(),
353 );
354 raw_options.as_mut().copy_from_slice(raw_options_bytes);
355 let body = Buf::new(
356 packet.into_body().complete().expect("unexpected incomplete IP body"),
357 ..,
358 );
359 Ok((Out(ForwardedIpv4PacketBuilder { builder, raw_options }), IpInvariant(body)))
360 },
361 |forwarded| {
362 if !forwarded.reassembled() {
371 return Err(FragmentationError::NotAllowed);
372 }
373 let mut buffer = forwarded.buffer().as_ref();
374 let packet =
377 Ipv6Packet::parse(&mut buffer, ()).expect("ForwardedPacket must be parseable");
378 let builder = packet.per_fragment_builder();
379 let body = Buf::new(&forwarded.buffer().as_ref()[builder.header_len()..], ..);
380 Ok((Out(ForwardedIpv6PacketBuilder(builder)), IpInvariant(body)))
381 },
382 )
383 .map(|(Out(builder), IpInvariant(body))| (builder, body))
384 }
385}
386
387pub struct ForwardedIpv4PacketBuilder {
388 builder: Ipv4PacketBuilder,
389 raw_options: Buf<[u8; packet_formats::ipv4::MAX_OPTIONS_LEN]>,
390}
391
392impl FragmentableIpPacketBuilder<Ipv4> for ForwardedIpv4PacketBuilder {
393 fn header_sizes(&self) -> HeaderSizes {
394 let Self { builder, raw_options } = self;
395 if raw_options.is_empty() {
396 builder.header_sizes()
397 } else {
398 let options = packet_formats::ipv4::Options::parse(raw_options.as_ref())
399 .expect("must hold valid options");
400 Ipv4PacketBuilderWithOptions::new_with_records_iter(builder.clone(), options.iter())
401 .header_sizes()
402 }
403 }
404
405 fn builder_at(
406 &self,
407 offset: FragmentOffset,
408 position: FragmentPosition,
409 (): (),
410 ) -> impl PacketBuilder<NetworkSerializationContext> + '_ {
411 let Self { builder, raw_options } = self;
412 let mut builder = builder.clone();
413 set_ipv4_fragment(&mut builder, offset, position);
414 let options = packet_formats::ipv4::Options::parse(raw_options.as_ref())
415 .expect("must hold valid options");
416 Ipv4PacketBuilderWithOptions::new_with_records_iter(builder.clone(), options.into_iter())
417 .with_fragment_options(position == FragmentPosition::First)
418 }
419}
420
421pub struct ForwardedIpv6PacketBuilder(Ipv6PerFragmentHeaderBuilder<Vec<u8>>);
422
423impl FragmentableIpPacketBuilder<Ipv6> for ForwardedIpv6PacketBuilder {
424 fn header_sizes(&self) -> HeaderSizes {
425 let size = self.0.header_len() + IPV6_FRAGMENT_EXT_HDR_LEN;
426 HeaderSizes { first: size, remaining: size }
427 }
428
429 fn builder_at(
430 &self,
431 offset: FragmentOffset,
432 position: FragmentPosition,
433 identifier: u32,
434 ) -> impl PacketBuilder<NetworkSerializationContext> + '_ {
435 Ipv6PacketBuilderWithFragmentHeader::new(
436 self.0.as_ref(),
437 offset,
438 position != FragmentPosition::Last,
439 identifier,
440 )
441 }
442}
443
444pub(crate) trait FragmentationIdGenContext {
449 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId;
450}
451
452#[derive(GenericOverIp)]
453#[generic_over_ip(I, Ip)]
454struct WrapFragmentationId<I: FragmentationIpExt>(I::FragmentationId);
455
456impl<BC> FragmentationIdGenContext for BC
457where
458 BC: RngContext,
459{
460 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId {
461 let WrapFragmentationId(identifier) = I::map_ip_out(
462 self,
463 |_| WrapFragmentationId(()),
464 |rng| {
465 WrapFragmentationId(rng.rng().random_range(1..=u32::MAX))
473 },
474 );
475 identifier
476 }
477}
478
479pub(crate) struct IpFragmenter<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I> + 'a> {
480 builder: S::Builder<'a>,
481 body: S::Body<'a>,
482 consumed: usize,
483 max_fragment_body_first: usize,
484 max_fragment_body_remaining: usize,
485 identifier: I::FragmentationId,
486}
487
488fn maximum_fragment_body_with_header_and_mtu(
494 mtu: Mtu,
495 header: usize,
496) -> Result<usize, FragmentationError> {
497 let v = usize::from(mtu).checked_sub(header).ok_or(FragmentationError::MtuTooSmall)?;
498 let v = v & !0x07usize;
501
502 if v == 0 {
503 return Err(FragmentationError::MtuTooSmall);
506 }
507 Ok(v)
508}
509
510impl<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I>> IpFragmenter<'a, I, S> {
511 pub(crate) fn new<C: FragmentationIdGenContext>(
514 id_ctx: &mut C,
515 serializer: &'a S,
516 mtu: Mtu,
517 ) -> Result<Self, FragmentationError> {
518 let (builder, body) = serializer.builder_and_body()?;
519 let HeaderSizes { first, remaining } = builder.header_sizes();
520 let max_fragment_body_first = maximum_fragment_body_with_header_and_mtu(mtu, first)?;
521 let max_fragment_body_remaining =
522 maximum_fragment_body_with_header_and_mtu(mtu, remaining)?;
523
524 if body.as_ref().len() > MAX_FRAGMENT_OFFSET + max_fragment_body_remaining {
525 return Err(FragmentationError::BodyTooLong);
526 }
527
528 let identifier = id_ctx.generate_id::<I>();
529
530 Ok(Self {
531 builder,
532 body,
533 consumed: 0,
534 max_fragment_body_first,
535 max_fragment_body_remaining,
536 identifier,
537 })
538 }
539
540 pub(crate) fn next(&mut self) -> Option<(impl NetworkSerializer<Buffer = EmptyBuf>, bool)> {
549 let Self {
550 builder,
551 body,
552 consumed,
553 max_fragment_body_first,
554 max_fragment_body_remaining,
555 identifier,
556 } = self;
557 let body = &AsRef::as_ref(body)[*consumed..];
558 if body.is_empty() {
559 return None;
560 }
561 let first = *consumed == 0;
562 let max_fragment_body =
563 if first { max_fragment_body_first } else { max_fragment_body_remaining };
564 let take = body.len().min(*max_fragment_body);
565 let last = take == body.len();
566 let position = match (first, last) {
567 (true, true) => {
568 panic!("unnecessary fragmentation");
569 }
570 (true, false) => FragmentPosition::First,
571 (false, false) => FragmentPosition::Middle,
572 (false, true) => FragmentPosition::Last,
573 };
574 let fragment_offset = u16::try_from(*consumed).expect("fragment offset too large");
577 let fragment_offset =
581 FragmentOffset::new_with_bytes(fragment_offset).expect("invalid offset");
582 let fragment_builder = builder.builder_at(fragment_offset, position, *identifier);
583 let end = *consumed + take;
584 let has_more = body.len() > take;
585 let fragment_body = &body[..take];
586 *consumed = end;
587 Some((fragment_builder.wrap_body(fragment_body.into_serializer()), has_more))
588 }
589}
590
591fn can_fragment_ipv4(builder: &Ipv4PacketBuilder) -> Result<(), FragmentationError> {
592 if builder.read_df_flag() {
593 return Err(FragmentationError::NotAllowed);
594 }
595 Ok(())
596}
597
598fn set_ipv4_fragment(
599 builder: &mut Ipv4PacketBuilder,
600 offset: FragmentOffset,
601 position: FragmentPosition,
602) {
603 builder.mf_flag(position != FragmentPosition::Last);
604 builder.fragment_offset(offset);
605}
606
607#[derive(Default, Debug)]
609#[cfg_attr(
610 any(test, feature = "testutils"),
611 derive(PartialEq, netstack3_macros::CounterCollection)
612)]
613pub struct FragmentationCounters<C = Counter> {
614 pub fragmentation_required: C,
616 pub fragments: C,
618 pub error_not_allowed: C,
620 pub error_mtu_too_small: C,
622 pub error_body_too_long: C,
624 pub error_inner_size_limit_exceeded: C,
626 pub error_fragmented_serializer: C,
629}
630
631impl FragmentationCounters {
632 pub(crate) fn error_counter(&self, error: &FragmentationError) -> &Counter {
633 match error {
634 FragmentationError::NotAllowed => &self.error_not_allowed,
635 FragmentationError::MtuTooSmall => &self.error_mtu_too_small,
636 FragmentationError::BodyTooLong => &self.error_body_too_long,
637 FragmentationError::SizeLimitExceeded => &self.error_inner_size_limit_exceeded,
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 netstack3_filter::FilterIpExt;
650 use packet::{Buffer, BufferView, GrowBuffer, Serializer};
651 use packet_formats::ip::IpProto;
652 use packet_formats::ipv4::Ipv4Packet;
653 use packet_formats::ipv6::ext_hdrs::{
654 ExtensionHeaderOptionAction, HopByHopOption, HopByHopOptionData, Ipv6ExtensionHeader,
655 };
656 use packet_formats::ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketBuilder};
657 use test_case::test_case;
658
659 const TEST_MTU: Mtu = Ipv6::MINIMUM_LINK_MTU;
660
661 fn gen_body(len: usize) -> Vec<u8> {
662 (0u8..=251).cycle().take(len).collect::<Vec<u8>>()
665 }
666
667 impl<'a, I: FragmentationIpExt, S: FragmentableIpSerializer<I>> IpFragmenter<'a, I, S> {
668 fn next_serialized(&mut self) -> Buf<Vec<u8>> {
669 self.next()
670 .expect("no more fragments")
671 .0
672 .serialize_vec_outer(&mut NetworkSerializationContext::default())
673 .map_err(|(err, _serializer)| err)
674 .unwrap()
675 .unwrap_b()
676 }
677 }
678
679 trait FragmentationTestEnv<I: FragmentationIpExt> {
680 fn new_serializer<'a>(
681 &self,
682 body: &'a [u8],
683 ) -> impl FragmentableIpSerializer<I, Buffer: Buffer> + 'a;
684 fn check_fragment(
685 &self,
686 fragment: &mut Buf<Vec<u8>>,
687 position: FragmentPosition,
688 offset: usize,
689 );
690 }
691
692 #[derive(Default)]
693 struct Ipv4TestEnv {
694 dont_frag: bool,
695 }
696
697 impl Ipv4TestEnv {
698 const fn dont_frag() -> Self {
699 Self { dont_frag: true }
700 }
701 }
702
703 const IPV4_ID: u16 = 0x1234;
704 fn new_ipv4_packet_builder(dont_frag: bool) -> Ipv4PacketBuilder {
705 let mut builder = Ipv4PacketBuilder::new(
706 TEST_ADDRS_V4.local_ip,
707 TEST_ADDRS_V4.remote_ip,
708 1,
709 IpProto::Udp.into(),
710 );
711 builder.id(IPV4_ID);
712 builder.df_flag(dont_frag);
713 builder
714 }
715
716 fn parse_and_check_ipv4_packet(
717 fragment: &mut Buf<Vec<u8>>,
718 position: FragmentPosition,
719 offset: usize,
720 ) -> Ipv4Packet<&[u8]> {
721 let packet = Ipv4Packet::parse(fragment.buffer_view(), ()).expect("parse fragment");
722 assert_eq!(packet.src_ip(), TEST_ADDRS_V4.local_ip.get());
723 assert_eq!(packet.dst_ip(), TEST_ADDRS_V4.remote_ip.get());
724 assert_eq!(packet.ttl(), 1);
725 assert_eq!(packet.id(), IPV4_ID);
726 assert_eq!(packet.proto(), IpProto::Udp.into());
727 assert_eq!(packet.mf_flag(), position != FragmentPosition::Last);
728 assert_eq!(usize::from(packet.fragment_offset().into_bytes()), offset);
729 packet
730 }
731
732 impl FragmentationTestEnv<Ipv4> for Ipv4TestEnv {
733 fn new_serializer<'a>(
734 &self,
735 body: &'a [u8],
736 ) -> impl FragmentableIpSerializer<Ipv4, Buffer: Buffer> + 'a {
737 let Self { dont_frag } = self;
738 new_ipv4_packet_builder(*dont_frag).wrap_body(body.into_serializer())
739 }
740
741 fn check_fragment(
742 &self,
743 fragment: &mut Buf<Vec<u8>>,
744 position: FragmentPosition,
745 offset: usize,
746 ) {
747 let _ = parse_and_check_ipv4_packet(fragment, position, offset);
748 }
749 }
750
751 #[derive(Default)]
752 struct Ipv4WithOptionsTestEnv(Ipv4TestEnv);
753
754 const FAKE_OPTION_COPIED_KIND: u8 = 255;
756 const FAKE_OPTION_COPIED: [u8; 1] = [255];
757 const FAKE_OPTION_NOT_COPIED_KIND: u8 = 127;
758 const FAKE_OPTION_NOT_COPIED: [u8; 1] = [127];
759
760 impl FragmentationTestEnv<Ipv4> for Ipv4WithOptionsTestEnv {
761 fn new_serializer<'a>(
762 &self,
763 body: &'a [u8],
764 ) -> impl FragmentableIpSerializer<Ipv4, Buffer: Buffer> + 'a {
765 let Self(Ipv4TestEnv { dont_frag }) = self;
766
767 Ipv4PacketBuilderWithOptions::new(
768 new_ipv4_packet_builder(*dont_frag),
769 [
770 Ipv4Option::Unrecognized {
771 kind: FAKE_OPTION_COPIED_KIND,
772 data: &FAKE_OPTION_COPIED[..],
773 },
774 Ipv4Option::Unrecognized {
775 kind: FAKE_OPTION_NOT_COPIED_KIND,
776 data: &FAKE_OPTION_NOT_COPIED[..],
777 },
778 ],
779 )
780 .unwrap()
781 .wrap_body(body.into_serializer())
782 }
783
784 fn check_fragment(
785 &self,
786 fragment: &mut Buf<Vec<u8>>,
787 position: FragmentPosition,
788 offset: usize,
789 ) {
790 let packet = parse_and_check_ipv4_packet(fragment, position, offset);
791 let (copied, not_copied) = packet.iter_options().fold(
792 (false, false),
793 |(mut copied, mut not_copied), option| {
794 let (kind, data) = assert_matches!(option,
795 Ipv4Option::Unrecognized{ kind, data } => (kind, data)
796 );
797 assert_eq!(data.len(), 1);
798 assert_eq!(data[0], kind);
799 let seen = match kind {
800 FAKE_OPTION_COPIED_KIND => &mut copied,
801 FAKE_OPTION_NOT_COPIED_KIND => &mut not_copied,
802 k => panic!("unexpected option {k}"),
803 };
804 assert_eq!(core::mem::replace(seen, true), false);
805 (copied, not_copied)
806 },
807 );
808 assert_eq!(copied, true, "must be copied on all fragments {position:?}");
809 assert_eq!(
810 not_copied,
811 position == FragmentPosition::First,
812 "must only be in first fragment {position:?}"
813 );
814 }
815 }
816
817 struct ForwardingTestEnv<E> {
818 inner: E,
819 reassembled: bool,
820 }
821
822 impl<E> ForwardingTestEnv<E> {
823 fn new(inner: E) -> Self {
824 Self { inner, reassembled: false }
825 }
826
827 fn new_reassembled(inner: E) -> Self {
828 Self { inner, reassembled: true }
829 }
830 }
831
832 impl<I: FragmentationIpExt + FilterIpExt, E: FragmentationTestEnv<I>> FragmentationTestEnv<I>
833 for ForwardingTestEnv<E>
834 {
835 fn new_serializer<'a>(
836 &self,
837 body: &'a [u8],
838 ) -> impl FragmentableIpSerializer<I, Buffer: Buffer> + 'a {
839 use packet_formats::ip::IpPacket as _;
840 let Self { inner, reassembled } = self;
841 let mut buffer = inner
842 .new_serializer(body)
843 .serialize_outer(
844 &mut NetworkSerializationContext::default(),
845 packet::NoReuseBufferProvider(packet::new_buf_vec),
846 )
847 .map_err(|(err, _)| err)
848 .unwrap();
849 let packet =
850 <I::Packet<_> as ParsablePacket<_, _>>::parse(buffer.buffer_view(), ()).unwrap();
851 let src_addr = packet.src_ip();
852 let dst_addr = packet.dst_ip();
853 let proto = packet.proto();
854 let meta = packet.parse_metadata();
855 drop(packet);
856 ForwardedPacket::new(src_addr, dst_addr, proto, meta, buffer, *reassembled)
857 }
858 fn check_fragment(
859 &self,
860 fragment: &mut Buf<Vec<u8>>,
861 position: FragmentPosition,
862 offset: usize,
863 ) {
864 let Self { inner, reassembled: _ } = self;
865 inner.check_fragment(fragment, position, offset)
866 }
867 }
868
869 struct Ipv6TestEnv;
870
871 const IPV6_ID: u32 = 0x1234ABCD;
872
873 impl FragmentationTestEnv<Ipv6> for Ipv6TestEnv {
874 fn new_serializer<'a>(
875 &self,
876 body: &'a [u8],
877 ) -> impl FragmentableIpSerializer<Ipv6, Buffer: Buffer> + 'a {
878 Ipv6PacketBuilder::new(
879 TEST_ADDRS_V6.local_ip,
880 TEST_ADDRS_V6.remote_ip,
881 1,
882 IpProto::Udp.into(),
883 )
884 .wrap_body(body.into_serializer())
885 }
886
887 fn check_fragment(
888 &self,
889 fragment: &mut Buf<Vec<u8>>,
890 position: FragmentPosition,
891 offset: usize,
892 ) {
893 let packet = Ipv6Packet::parse(fragment.buffer_view(), ()).unwrap();
894 assert_eq!(packet.src_ip(), TEST_ADDRS_V6.local_ip.get());
895 assert_eq!(packet.dst_ip(), TEST_ADDRS_V6.remote_ip.get());
896 assert_eq!(packet.hop_limit(), 1);
897 assert_eq!(packet.proto(), IpProto::Udp.into());
898 let fragment = packet
899 .iter_extension_hdrs()
900 .find_map(|h| match h {
901 Ipv6ExtensionHeader::Fragment { fragment_data } => Some(fragment_data),
902 _ => None,
903 })
904 .expect("no fragment header");
905 assert_eq!(fragment.identification(), IPV6_ID);
906 assert_eq!(usize::from(fragment.fragment_offset().into_bytes()), offset);
907 assert_eq!(fragment.m_flag(), position != FragmentPosition::Last);
908 }
909 }
910
911 #[derive(Default)]
912 struct Ipv6WithOptionsTestEnv;
913
914 impl FragmentationTestEnv<Ipv6> for Ipv6WithOptionsTestEnv {
915 fn new_serializer<'a>(
916 &self,
917 body: &'a [u8],
918 ) -> impl FragmentableIpSerializer<Ipv6, Buffer: Buffer> + 'a {
919 packet_formats::ipv6::Ipv6PacketBuilderWithHbhOptions::new(
920 Ipv6PacketBuilder::new(
921 TEST_ADDRS_V6.local_ip,
922 TEST_ADDRS_V6.remote_ip,
923 1,
924 IpProto::Udp.into(),
925 ),
926 &[HopByHopOption {
929 action: ExtensionHeaderOptionAction::SkipAndContinue,
930 mutable: false,
931 data: HopByHopOptionData::RouterAlert { data: 0 },
932 }],
933 )
934 .unwrap()
935 .wrap_body(body.into_serializer())
936 }
937
938 fn check_fragment(
939 &self,
940 fragment: &mut Buf<Vec<u8>>,
941 position: FragmentPosition,
942 offset: usize,
943 ) {
944 let packet = Ipv6Packet::parse(fragment.buffer_view(), ()).unwrap();
945 assert_eq!(packet.src_ip(), TEST_ADDRS_V6.local_ip.get());
946 assert_eq!(packet.dst_ip(), TEST_ADDRS_V6.remote_ip.get());
947 assert_eq!(packet.hop_limit(), 1);
948 assert_eq!(packet.proto(), IpProto::Udp.into());
949 let ext_hdrs = packet.iter_extension_hdrs().collect::<Vec<_>>();
950 let (hbh, frag) = assert_matches!(&ext_hdrs[..], [hbh, frag] => (hbh, frag));
951 assert_matches!(hbh, Ipv6ExtensionHeader::HopByHopOptions { .. });
952 let fragment = assert_matches!(
953 frag, Ipv6ExtensionHeader::Fragment { fragment_data } => fragment_data
954 );
955 assert_eq!(fragment.identification(), IPV6_ID);
956 assert_eq!(usize::from(fragment.fragment_offset().into_bytes()), offset);
957 assert_eq!(fragment.m_flag(), position != FragmentPosition::Last);
958 }
959 }
960
961 struct FixedIdContext;
962 impl FragmentationIdGenContext for FixedIdContext {
963 fn generate_id<I: FragmentationIpExt>(&mut self) -> I::FragmentationId {
964 let WrapFragmentationId(id) =
965 I::map_ip_out((), |()| WrapFragmentationId(()), |()| WrapFragmentationId(IPV6_ID));
966 id
967 }
968 }
969
970 #[test_case::test_matrix(
971 [
972 Ipv4TestEnv::default(),
973 Ipv4WithOptionsTestEnv::default(),
974 ForwardingTestEnv::new(Ipv4TestEnv::default()),
975 ForwardingTestEnv::new(Ipv4WithOptionsTestEnv::default()),
976 ForwardingTestEnv::new_reassembled(Ipv6TestEnv),
977 ForwardingTestEnv::new_reassembled(Ipv6WithOptionsTestEnv),
978 Ipv6TestEnv,
979 Ipv6WithOptionsTestEnv,
980 ],
981 0..=2
982 )]
983 fn fragment<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(
984 env: E,
985 middle_fragments: usize,
986 ) {
987 let full_body = gen_body(usize::from(TEST_MTU) * (1 + middle_fragments));
992 let mut body_view = Buf::new(&full_body[..], ..);
993 let serializer = env.new_serializer(&full_body[..]);
994 let mut fragmenter = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU)
995 .expect("create fragmenter");
996
997 let mut frag = fragmenter.next_serialized();
998 env.check_fragment(&mut frag, FragmentPosition::First, body_view.prefix_len());
999 assert_eq!(
1000 frag.as_ref(),
1001 body_view.buffer_view().take_front(fragmenter.max_fragment_body_first).unwrap()
1002 );
1003
1004 for _ in 0..middle_fragments {
1005 let mut frag = fragmenter.next_serialized();
1006 env.check_fragment(&mut frag, FragmentPosition::Middle, body_view.prefix_len());
1007 assert_eq!(
1008 frag.as_ref(),
1009 body_view.buffer_view().take_front(fragmenter.max_fragment_body_remaining).unwrap()
1010 );
1011 }
1012
1013 let mut frag = fragmenter.next_serialized();
1014 env.check_fragment(&mut frag, FragmentPosition::Last, body_view.prefix_len());
1015 assert_eq!(frag.as_ref(), body_view.buffer_view().into_rest());
1016
1017 assert!(fragmenter.next().is_none());
1019 }
1020
1021 #[test_case(Ipv4TestEnv::dont_frag())]
1022 #[test_case(Ipv4WithOptionsTestEnv(Ipv4TestEnv::dont_frag()))]
1023 #[test_case(ForwardingTestEnv::new(Ipv4TestEnv::dont_frag()))]
1024 #[test_case(ForwardingTestEnv::new(Ipv6TestEnv))]
1025 #[test_case(ForwardingTestEnv::new(Ipv6WithOptionsTestEnv))]
1026 fn not_allowed<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
1027 let body = gen_body(usize::from(TEST_MTU));
1028 let serializer = env.new_serializer(&body[..]);
1029 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU).map(|_| ());
1030 assert_eq!(result, Err(FragmentationError::NotAllowed))
1031 }
1032
1033 #[test_case(Ipv4TestEnv::default())]
1034 #[test_case(Ipv4WithOptionsTestEnv::default())]
1035 #[test_case(ForwardingTestEnv::new(Ipv4TestEnv::default()))]
1036 #[test_case(ForwardingTestEnv::new_reassembled(Ipv6TestEnv))]
1037 #[test_case(ForwardingTestEnv::new_reassembled(Ipv6WithOptionsTestEnv))]
1038 #[test_case(Ipv6TestEnv)]
1039 #[test_case(Ipv6WithOptionsTestEnv)]
1040 fn mtu_too_small<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
1041 let body = gen_body(usize::from(TEST_MTU));
1042 let serializer = env.new_serializer(&body[..]);
1043 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, Mtu::new(10)).map(|_| ());
1044 assert_eq!(result, Err(FragmentationError::MtuTooSmall));
1045 }
1046
1047 #[test_case(Ipv4TestEnv::default())]
1048 #[test_case(Ipv4WithOptionsTestEnv::default())]
1049 #[test_case(Ipv6TestEnv)]
1050 #[test_case(Ipv6WithOptionsTestEnv)]
1051 fn body_too_long<I: FragmentationIpExt, E: FragmentationTestEnv<I>>(env: E) {
1052 let body = gen_body(MAX_FRAGMENT_OFFSET + usize::from(TEST_MTU));
1053 let serializer = env.new_serializer(&body[..]);
1054 let result = IpFragmenter::new(&mut FixedIdContext, &serializer, TEST_MTU).map(|_| ());
1055 assert_eq!(result, Err(FragmentationError::BodyTooLong));
1056 }
1057}