• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{defrag::*, *};
2 use std::collections::HashMap;
3 use std::vec::Vec;
4 
5 /// Pool of buffers to reconstruct multiple fragmented IP packets in
6 /// parallel (re-uses buffers to minimize allocations).
7 ///
8 /// It differentiates the packets based on their inner & outer vlan as well as
9 /// source and destination ip address and allows the user to add their own
10 /// custom "channel id" type to further differentiate different streams.
11 /// The custom channel id can be used to
12 ///
13 /// # This implementation is NOT safe against "Out of Memory" attacks
14 ///
15 /// If you use the [`IpDefragPool`] in an untrusted environment an attacker could
16 /// cause an "out of memory error" by opening up multiple parallel TP streams,
17 /// never ending them and filling them up with as much data as possible.
18 ///
19 /// Mitigations will hopefully be offered in future versions but if you have
20 /// take care right now you can still use [`IpDefragBuf`] directly and implement the
21 /// connection handling and mitigation yourself.
22 #[derive(Debug, Clone)]
23 pub struct IpDefragPool<Timestamp = (), CustomChannelId = ()>
24 where
25     Timestamp: Sized + core::fmt::Debug + Clone,
26     CustomChannelId: Sized + core::fmt::Debug + Clone + core::hash::Hash + Eq + PartialEq,
27 {
28     /// Currently reconstructing IP packets.
29     active: HashMap<IpFragId<CustomChannelId>, (IpDefragBuf, Timestamp)>,
30 
31     /// Data buffers that have finished receiving data and can be re-used.
32     finished_data_bufs: Vec<Vec<u8>>,
33 
34     /// Section buffers that have finished receiving data and can be re-used.
35     finished_section_bufs: Vec<Vec<IpFragRange>>,
36 }
37 
38 impl<Timestamp, CustomChannelId> IpDefragPool<Timestamp, CustomChannelId>
39 where
40     Timestamp: Sized + core::fmt::Debug + Clone,
41     CustomChannelId: Sized + core::fmt::Debug + Clone + core::hash::Hash + Eq + PartialEq,
42 {
new() -> IpDefragPool<Timestamp, CustomChannelId>43     pub fn new() -> IpDefragPool<Timestamp, CustomChannelId> {
44         IpDefragPool {
45             active: HashMap::new(),
46             finished_data_bufs: Vec::new(),
47             finished_section_bufs: Vec::new(),
48         }
49     }
50 
51     /// Add data from a sliced packet.
process_sliced_packet( &mut self, slice: &SlicedPacket, timestamp: Timestamp, channel_id: CustomChannelId, ) -> Result<Option<IpDefragPayloadVec>, IpDefragError>52     pub fn process_sliced_packet(
53         &mut self,
54         slice: &SlicedPacket,
55         timestamp: Timestamp,
56         channel_id: CustomChannelId,
57     ) -> Result<Option<IpDefragPayloadVec>, IpDefragError> {
58         // extract the fragment related data and skip non-fragmented packets
59         let (frag_id, offset, more_fragments, payload, is_ipv4) = match &slice.net {
60             Some(NetSlice::Ipv4(ipv4)) => {
61                 let header = ipv4.header();
62                 if false == header.is_fragmenting_payload() {
63                     // nothing to defragment here, skip packet
64                     return Ok(None);
65                 }
66 
67                 let (outer_vlan_id, inner_vlan_id) = match &slice.vlan {
68                     Some(VlanSlice::SingleVlan(s)) => (Some(s.vlan_identifier()), None),
69                     Some(VlanSlice::DoubleVlan(d)) => (
70                         Some(d.outer().vlan_identifier()),
71                         Some(d.inner().vlan_identifier()),
72                     ),
73                     None => (None, None),
74                 };
75 
76                 (
77                     IpFragId {
78                         outer_vlan_id,
79                         inner_vlan_id,
80                         ip: IpFragVersionSpecId::Ipv4 {
81                             source: header.source(),
82                             destination: header.destination(),
83                             identification: header.identification(),
84                         },
85                         payload_ip_number: ipv4.payload().ip_number,
86                         channel_id,
87                     },
88                     header.fragments_offset(),
89                     header.more_fragments(),
90                     ipv4.payload(),
91                     true,
92                 )
93             }
94             Some(NetSlice::Ipv6(ipv6)) => {
95                 // get fragmentation header
96                 let frag = {
97                     let mut f = None;
98                     for ext in ipv6.extensions().clone().into_iter() {
99                         use Ipv6ExtensionSlice::*;
100                         if let Fragment(frag_it) = ext {
101                             f = Some(frag_it);
102                             break;
103                         }
104                     }
105                     if let Some(f) = f {
106                         if f.is_fragmenting_payload() {
107                             f.to_header()
108                         } else {
109                             // nothing to defragment here, skip packet
110                             return Ok(None);
111                         }
112                     } else {
113                         // nothing to defragment here, skip packet
114                         return Ok(None);
115                     }
116                 };
117 
118                 let (outer_vlan_id, inner_vlan_id) = match &slice.vlan {
119                     Some(VlanSlice::SingleVlan(s)) => (Some(s.vlan_identifier()), None),
120                     Some(VlanSlice::DoubleVlan(d)) => (
121                         Some(d.outer().vlan_identifier()),
122                         Some(d.inner().vlan_identifier()),
123                     ),
124                     None => (None, None),
125                 };
126 
127                 // calculate frag id
128                 (
129                     IpFragId {
130                         outer_vlan_id,
131                         inner_vlan_id,
132                         ip: IpFragVersionSpecId::Ipv6 {
133                             source: ipv6.header().source(),
134                             destination: ipv6.header().destination(),
135                             identification: frag.identification,
136                         },
137                         payload_ip_number: ipv6.payload().ip_number,
138                         channel_id,
139                     },
140                     frag.fragment_offset,
141                     frag.more_fragments,
142                     ipv6.payload(),
143                     false,
144                 )
145             }
146             Some(NetSlice::Arp(_)) | None => {
147                 // nothing to defragment here, skip packet
148                 return Ok(None);
149             }
150         };
151 
152         // get the reconstruction buffer
153         use std::collections::hash_map::Entry;
154         match self.active.entry(frag_id) {
155             Entry::Occupied(mut entry) => {
156                 let buf = entry.get_mut();
157                 buf.0.add(offset, more_fragments, payload.payload)?;
158                 buf.1 = timestamp;
159                 if buf.0.is_complete() {
160                     let (defraged_payload, sections) = entry.remove().0.take_bufs();
161                     self.finished_section_bufs.push(sections);
162                     Ok(Some(IpDefragPayloadVec {
163                         ip_number: payload.ip_number,
164                         len_source: if is_ipv4 {
165                             LenSource::Ipv4HeaderTotalLen
166                         } else {
167                             LenSource::Ipv6HeaderPayloadLen
168                         },
169                         payload: defraged_payload,
170                     }))
171                 } else {
172                     Ok(None)
173                 }
174             }
175             Entry::Vacant(entry) => {
176                 let data_buf = if let Some(mut d) = self.finished_data_bufs.pop() {
177                     d.clear();
178                     d
179                 } else {
180                     Vec::with_capacity(payload.payload.len() * 2)
181                 };
182                 let sections = if let Some(mut s) = self.finished_section_bufs.pop() {
183                     s.clear();
184                     s
185                 } else {
186                     Vec::with_capacity(4)
187                 };
188 
189                 let mut defrag_buf = IpDefragBuf::new(payload.ip_number, data_buf, sections);
190                 match defrag_buf.add(offset, more_fragments, payload.payload) {
191                     Ok(()) => {
192                         // no need to check if the defrag is done as the
193                         // packet can not be defragmented on initial add
194                         // otherwise `is_fragmenting_payload` would have
195                         // been false
196                         entry.insert((defrag_buf, timestamp));
197                         Ok(None)
198                     }
199                     Err(err) => {
200                         // return the buffers
201                         let (data_buf, sections) = defrag_buf.take_bufs();
202                         self.finished_data_bufs.push(data_buf);
203                         self.finished_section_bufs.push(sections);
204                         Err(err)
205                     }
206                 }
207             }
208         }
209     }
210 
211     /// Returns a buffer to the pool so it can be re-used.
return_buf(&mut self, buf: IpDefragPayloadVec)212     pub fn return_buf(&mut self, buf: IpDefragPayloadVec) {
213         self.finished_data_bufs.push(buf.payload);
214     }
215 
216     /// Retains only the elements specified by the predicate.
retain<F>(&mut self, f: F) where F: Fn(&Timestamp) -> bool,217     pub fn retain<F>(&mut self, f: F)
218     where
219         F: Fn(&Timestamp) -> bool,
220     {
221         if self.active.iter().any(|(_, (_, t))| false == f(t)) {
222             self.active = self
223                 .active
224                 .drain()
225                 .filter_map(|(k, v)| {
226                     if f(&v.1) {
227                         Some((k, v))
228                     } else {
229                         let (data, sections) = v.0.take_bufs();
230                         self.finished_data_bufs.push(data);
231                         self.finished_section_bufs.push(sections);
232                         None
233                     }
234                 })
235                 .collect();
236         }
237     }
238 }
239 
240 impl<Timestamp, CustomChannelId> Default for IpDefragPool<Timestamp, CustomChannelId>
241 where
242     Timestamp: Sized + core::fmt::Debug + Clone,
243     CustomChannelId: Sized + core::fmt::Debug + Clone + core::hash::Hash + Eq + PartialEq,
244 {
default() -> Self245     fn default() -> Self {
246         Self::new()
247     }
248 }
249 
250 #[cfg(test)]
251 mod test {
252     use std::cmp::max;
253 
254     use super::*;
255 
256     #[test]
new()257     fn new() {
258         {
259             let pool = IpDefragPool::<(), ()>::new();
260             assert_eq!(pool.active.len(), 0);
261             assert_eq!(pool.finished_data_bufs.len(), 0);
262             assert_eq!(pool.finished_section_bufs.len(), 0);
263         }
264         {
265             let pool = IpDefragPool::<u32, (u32, u32)>::new();
266             assert_eq!(pool.active.len(), 0);
267             assert_eq!(pool.finished_data_bufs.len(), 0);
268             assert_eq!(pool.finished_section_bufs.len(), 0);
269         }
270     }
271 
272     #[test]
default()273     fn default() {
274         {
275             let pool: IpDefragPool<(), ()> = Default::default();
276             assert_eq!(pool.active.len(), 0);
277             assert_eq!(pool.finished_data_bufs.len(), 0);
278             assert_eq!(pool.finished_section_bufs.len(), 0);
279         }
280         {
281             let pool: IpDefragPool<u32, (u32, u32)> = Default::default();
282             assert_eq!(pool.active.len(), 0);
283             assert_eq!(pool.finished_data_bufs.len(), 0);
284             assert_eq!(pool.finished_section_bufs.len(), 0);
285         }
286     }
287 
build_packet<CustomChannelId: core::hash::Hash + Eq + PartialEq + Clone + Sized>( id: IpFragId<CustomChannelId>, offset: u16, more: bool, payload: &[u8], ) -> Vec<u8>288     fn build_packet<CustomChannelId: core::hash::Hash + Eq + PartialEq + Clone + Sized>(
289         id: IpFragId<CustomChannelId>,
290         offset: u16,
291         more: bool,
292         payload: &[u8],
293     ) -> Vec<u8> {
294         let mut buf = Vec::with_capacity(
295             Ethernet2Header::LEN
296                 + SingleVlanHeader::LEN
297                 + SingleVlanHeader::LEN
298                 + max(
299                     Ipv4Header::MIN_LEN,
300                     Ipv6Header::LEN + Ipv6FragmentHeader::LEN,
301                 )
302                 + payload.len(),
303         );
304 
305         let ip_ether_type = match id.ip {
306             IpFragVersionSpecId::Ipv4 {
307                 source: _,
308                 destination: _,
309                 identification: _,
310             } => EtherType::IPV4,
311             IpFragVersionSpecId::Ipv6 {
312                 source: _,
313                 destination: _,
314                 identification: _,
315             } => EtherType::IPV6,
316         };
317 
318         buf.extend_from_slice(
319             &Ethernet2Header {
320                 source: [0; 6],
321                 destination: [0; 6],
322                 ether_type: if id.outer_vlan_id.is_some() || id.inner_vlan_id.is_some() {
323                     EtherType::VLAN_TAGGED_FRAME
324                 } else {
325                     ip_ether_type
326                 },
327             }
328             .to_bytes(),
329         );
330 
331         if let Some(vlan_id) = id.outer_vlan_id {
332             buf.extend_from_slice(
333                 &SingleVlanHeader {
334                     pcp: VlanPcp::try_new(0).unwrap(),
335                     drop_eligible_indicator: false,
336                     vlan_id,
337                     ether_type: if id.inner_vlan_id.is_some() {
338                         EtherType::VLAN_TAGGED_FRAME
339                     } else {
340                         ip_ether_type
341                     },
342                 }
343                 .to_bytes(),
344             );
345         }
346 
347         if let Some(vlan_id) = id.inner_vlan_id {
348             buf.extend_from_slice(
349                 &SingleVlanHeader {
350                     pcp: VlanPcp::try_new(0).unwrap(),
351                     drop_eligible_indicator: false,
352                     vlan_id,
353                     ether_type: ip_ether_type,
354                 }
355                 .to_bytes(),
356             );
357         }
358 
359         match id.ip {
360             IpFragVersionSpecId::Ipv4 {
361                 source,
362                 destination,
363                 identification,
364             } => {
365                 let mut header = Ipv4Header {
366                     identification,
367                     more_fragments: more,
368                     fragment_offset: IpFragOffset::try_new(offset).unwrap(),
369                     protocol: id.payload_ip_number,
370                     source,
371                     destination,
372                     total_len: (Ipv4Header::MIN_LEN + payload.len()) as u16,
373                     time_to_live: 2,
374                     ..Default::default()
375                 };
376                 header.header_checksum = header.calc_header_checksum();
377                 buf.extend_from_slice(&header.to_bytes());
378             }
379             IpFragVersionSpecId::Ipv6 {
380                 source,
381                 destination,
382                 identification,
383             } => {
384                 buf.extend_from_slice(
385                     &Ipv6Header {
386                         traffic_class: 0,
387                         flow_label: Default::default(),
388                         payload_length: (payload.len() + Ipv6FragmentHeader::LEN + 8) as u16,
389                         next_header: IpNumber::IPV6_FRAGMENTATION_HEADER,
390                         hop_limit: 2,
391                         source,
392                         destination,
393                     }
394                     .to_bytes(),
395                 );
396                 buf.extend_from_slice(
397                     &Ipv6FragmentHeader {
398                         next_header: IpNumber::IPV6_ROUTE_HEADER,
399                         fragment_offset: IpFragOffset::try_new(offset).unwrap(),
400                         more_fragments: more,
401                         identification,
402                     }
403                     .to_bytes(),
404                 );
405                 buf.extend_from_slice(
406                     &{
407                         let mut h: Ipv6RawExtHeader = Default::default();
408                         h.next_header = id.payload_ip_number;
409                         h
410                     }
411                     .to_bytes(),
412                 );
413             }
414         }
415         buf.extend_from_slice(payload);
416         buf
417     }
418 
419     #[test]
process_sliced_packet()420     fn process_sliced_packet() {
421         // non ip packet
422         {
423             let mut pool = IpDefragPool::<(), ()>::new();
424             let pslice = SlicedPacket {
425                 link: None,
426                 vlan: None,
427                 net: None,
428                 transport: None,
429             };
430             let v = pool.process_sliced_packet(&pslice, (), ());
431             assert_eq!(Ok(None), v);
432             assert_eq!(pool.active.len(), 0);
433             assert_eq!(pool.finished_data_bufs.len(), 0);
434             assert_eq!(pool.finished_section_bufs.len(), 0);
435         }
436 
437         // v4 non fragmented
438         {
439             let mut pool = IpDefragPool::<(), ()>::new();
440             let pdata = build_packet(
441                 IpFragId {
442                     outer_vlan_id: None,
443                     inner_vlan_id: None,
444                     ip: IpFragVersionSpecId::Ipv4 {
445                         source: [0; 4],
446                         destination: [0; 4],
447                         identification: 0,
448                     },
449                     payload_ip_number: IpNumber::UDP,
450                     channel_id: (),
451                 },
452                 0,
453                 false,
454                 &UdpHeader {
455                     source_port: 0,
456                     destination_port: 0,
457                     length: 0,
458                     checksum: 0,
459                 }
460                 .to_bytes(),
461             );
462             let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
463             let v = pool.process_sliced_packet(&pslice, (), ());
464             assert_eq!(Ok(None), v);
465 
466             // check the effect had no effect
467             assert_eq!(pool.active.len(), 0);
468             assert_eq!(pool.finished_data_bufs.len(), 0);
469             assert_eq!(pool.finished_section_bufs.len(), 0);
470         }
471 
472         // v6 non fragmented
473         {
474             let mut pool = IpDefragPool::<(), ()>::new();
475             let pdata = build_packet(
476                 IpFragId {
477                     outer_vlan_id: None,
478                     inner_vlan_id: None,
479                     ip: IpFragVersionSpecId::Ipv6 {
480                         source: [0; 16],
481                         destination: [0; 16],
482                         identification: 0,
483                     },
484                     payload_ip_number: IpNumber::UDP,
485                     channel_id: (),
486                 },
487                 0,
488                 false,
489                 &UdpHeader {
490                     source_port: 0,
491                     destination_port: 0,
492                     length: 0,
493                     checksum: 0,
494                 }
495                 .to_bytes(),
496             );
497             let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
498             let v = pool.process_sliced_packet(&pslice, (), ());
499             assert_eq!(Ok(None), v);
500 
501             // check the effect had no effect
502             assert_eq!(pool.active.len(), 0);
503             assert_eq!(pool.finished_data_bufs.len(), 0);
504             assert_eq!(pool.finished_section_bufs.len(), 0);
505         }
506 
507         // v4 & v6 basic test
508         {
509             let frag_ids = [
510                 // v4 (no vlan)
511                 IpFragId {
512                     outer_vlan_id: None,
513                     inner_vlan_id: None,
514                     ip: IpFragVersionSpecId::Ipv4 {
515                         source: [1, 2, 3, 4],
516                         destination: [5, 6, 7, 8],
517                         identification: 9,
518                     },
519                     payload_ip_number: IpNumber::UDP,
520                     channel_id: (),
521                 },
522                 // v4 (single vlan)
523                 IpFragId {
524                     outer_vlan_id: Some(VlanId::try_new(12).unwrap()),
525                     inner_vlan_id: None,
526                     ip: IpFragVersionSpecId::Ipv4 {
527                         source: [1, 2, 3, 4],
528                         destination: [5, 6, 7, 8],
529                         identification: 9,
530                     },
531                     payload_ip_number: IpNumber::UDP,
532                     channel_id: (),
533                 },
534                 // v4 (double vlan)
535                 IpFragId {
536                     outer_vlan_id: Some(VlanId::try_new(12).unwrap()),
537                     inner_vlan_id: Some(VlanId::try_new(23).unwrap()),
538                     ip: IpFragVersionSpecId::Ipv4 {
539                         source: [1, 2, 3, 4],
540                         destination: [5, 6, 7, 8],
541                         identification: 9,
542                     },
543                     payload_ip_number: IpNumber::UDP,
544                     channel_id: (),
545                 },
546                 // v6 (no vlan)
547                 IpFragId {
548                     outer_vlan_id: None,
549                     inner_vlan_id: None,
550                     ip: IpFragVersionSpecId::Ipv6 {
551                         source: [0; 16],
552                         destination: [0; 16],
553                         identification: 0,
554                     },
555                     payload_ip_number: IpNumber::UDP,
556                     channel_id: (),
557                 },
558                 // v6 (single vlan)
559                 IpFragId {
560                     outer_vlan_id: Some(VlanId::try_new(12).unwrap()),
561                     inner_vlan_id: None,
562                     ip: IpFragVersionSpecId::Ipv6 {
563                         source: [0; 16],
564                         destination: [0; 16],
565                         identification: 0,
566                     },
567                     payload_ip_number: IpNumber::UDP,
568                     channel_id: (),
569                 },
570                 // v6 (double vlan)
571                 IpFragId {
572                     outer_vlan_id: Some(VlanId::try_new(12).unwrap()),
573                     inner_vlan_id: Some(VlanId::try_new(23).unwrap()),
574                     ip: IpFragVersionSpecId::Ipv6 {
575                         source: [0; 16],
576                         destination: [0; 16],
577                         identification: 0,
578                     },
579                     payload_ip_number: IpNumber::UDP,
580                     channel_id: (),
581                 },
582             ];
583 
584             let mut pool = IpDefragPool::<(), ()>::new();
585 
586             for frag_id in frag_ids {
587                 {
588                     let pdata = build_packet(frag_id.clone(), 0, true, &[1, 2, 3, 4, 5, 6, 7, 8]);
589                     let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
590                     let v = pool.process_sliced_packet(&pslice, (), ());
591                     assert_eq!(Ok(None), v);
592 
593                     // check the frag id was correctly calculated
594                     assert_eq!(1, pool.active.len());
595                     assert_eq!(pool.active.iter().next().unwrap().0, &frag_id);
596                 }
597 
598                 {
599                     let pdata = build_packet(
600                         frag_id.clone(),
601                         1,
602                         true,
603                         &[
604                             9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
605                         ],
606                     );
607                     let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
608                     let v = pool.process_sliced_packet(&pslice, (), ());
609                     assert_eq!(Ok(None), v);
610 
611                     // check the frag id was correctly calculated
612                     assert_eq!(1, pool.active.len());
613                     assert_eq!(pool.active.iter().next().unwrap().0, &frag_id);
614                 }
615 
616                 {
617                     let pdata = build_packet(frag_id.clone(), 3, false, &[25, 26]);
618                     let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
619                     let v = pool
620                         .process_sliced_packet(&pslice, (), ())
621                         .unwrap()
622                         .unwrap();
623                     assert_eq!(v.ip_number, IpNumber::UDP);
624                     assert_eq!(
625                         v.len_source,
626                         if matches!(
627                             frag_id.ip,
628                             IpFragVersionSpecId::Ipv4 {
629                                 source: _,
630                                 destination: _,
631                                 identification: _
632                             }
633                         ) {
634                             LenSource::Ipv4HeaderTotalLen
635                         } else {
636                             LenSource::Ipv6HeaderPayloadLen
637                         }
638                     );
639                     assert_eq!(
640                         v.payload,
641                         &[
642                             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
643                             21, 22, 23, 24, 25, 26
644                         ]
645                     );
646 
647                     // there should be nothing left
648                     assert_eq!(pool.active.len(), 0);
649                     assert_eq!(pool.finished_data_bufs.len(), 0);
650                     assert_eq!(pool.finished_section_bufs.len(), 1);
651 
652                     // return buffer
653                     pool.return_buf(v);
654 
655                     assert_eq!(pool.active.len(), 0);
656                     assert_eq!(pool.finished_data_bufs.len(), 1);
657                     assert_eq!(pool.finished_section_bufs.len(), 1);
658                 }
659             }
660         }
661 
662         // ipv6 no frag header
663         {
664             // build packet without ipv6
665             let pdata = {
666                 let mut v = Vec::with_capacity(Ipv6Header::LEN + UdpHeader::LEN + 16);
667                 v.extend_from_slice(
668                     &Ipv6Header {
669                         traffic_class: 0,
670                         flow_label: Ipv6FlowLabel::try_new(0).unwrap(),
671                         payload_length: UdpHeader::LEN_U16 + 16,
672                         next_header: IpNumber::UDP,
673                         hop_limit: 2,
674                         source: [0; 16],
675                         destination: [0; 16],
676                     }
677                     .to_bytes(),
678                 );
679                 v.extend_from_slice(
680                     &UdpHeader {
681                         source_port: 1234,
682                         destination_port: 2345,
683                         length: UdpHeader::LEN_U16 + 10,
684                         checksum: 0,
685                     }
686                     .to_bytes(),
687                 );
688                 v.extend_from_slice(&[0; 16]);
689                 v
690             };
691             let slice = SlicedPacket::from_ip(&pdata).unwrap();
692 
693             let mut pool = IpDefragPool::<(), ()>::new();
694             assert_eq!(Ok(None), pool.process_sliced_packet(&slice, (), ()));
695             assert_eq!(pool.active.len(), 0);
696             assert_eq!(pool.finished_data_bufs.len(), 0);
697             assert_eq!(pool.finished_section_bufs.len(), 0);
698         }
699 
700         // error in initial packet
701         {
702             let frag_ids = [
703                 // v4
704                 IpFragId {
705                     outer_vlan_id: None,
706                     inner_vlan_id: None,
707                     ip: IpFragVersionSpecId::Ipv4 {
708                         source: [1, 2, 3, 4],
709                         destination: [5, 6, 7, 8],
710                         identification: 9,
711                     },
712                     payload_ip_number: IpNumber::UDP,
713                     channel_id: (),
714                 },
715                 // v6
716                 IpFragId {
717                     outer_vlan_id: None,
718                     inner_vlan_id: None,
719                     ip: IpFragVersionSpecId::Ipv6 {
720                         source: [0; 16],
721                         destination: [0; 16],
722                         identification: 0,
723                     },
724                     payload_ip_number: IpNumber::UDP,
725                     channel_id: (),
726                 },
727             ];
728             let mut pool = IpDefragPool::<(), ()>::new();
729 
730             for frag_id in frag_ids {
731                 let pdata = build_packet(frag_id.clone(), 0, true, &[0; 7]);
732                 let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
733                 let v = pool.process_sliced_packet(&pslice, (), ());
734                 assert_eq!(
735                     Err(IpDefragError::UnalignedFragmentPayloadLen {
736                         offset: IpFragOffset::try_new(0).unwrap(),
737                         payload_len: 7
738                     }),
739                     v
740                 );
741                 assert_eq!(0, pool.active.len());
742             }
743         }
744 
745         // error in followup packet
746         {
747             let frag_ids = [
748                 // v4
749                 IpFragId {
750                     outer_vlan_id: None,
751                     inner_vlan_id: None,
752                     ip: IpFragVersionSpecId::Ipv4 {
753                         source: [1, 2, 3, 4],
754                         destination: [5, 6, 7, 8],
755                         identification: 9,
756                     },
757                     payload_ip_number: IpNumber::UDP,
758                     channel_id: (),
759                 },
760                 // v6
761                 IpFragId {
762                     outer_vlan_id: None,
763                     inner_vlan_id: None,
764                     ip: IpFragVersionSpecId::Ipv6 {
765                         source: [0; 16],
766                         destination: [0; 16],
767                         identification: 0,
768                     },
769                     payload_ip_number: IpNumber::UDP,
770                     channel_id: (),
771                 },
772             ];
773 
774             for frag_id in frag_ids {
775                 let mut pool = IpDefragPool::<(), ()>::new();
776 
777                 // initial packet
778                 {
779                     let pdata = build_packet(frag_id.clone(), 0, true, &[1, 2, 3, 4, 5, 6, 7, 8]);
780                     let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
781                     let v = pool.process_sliced_packet(&pslice, (), ());
782                     assert_eq!(Ok(None), v);
783 
784                     // check the frag id was correctly calculated
785                     assert_eq!(1, pool.active.len());
786                     assert_eq!(pool.active.iter().next().unwrap().0, &frag_id);
787                 }
788 
789                 // follow up packet error
790                 {
791                     let pdata = build_packet(
792                         frag_id.clone(),
793                         1,
794                         true,
795                         &[9, 10, 11, 12, 13, 14, 15, 16, 17],
796                     );
797                     let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
798                     let v = pool.process_sliced_packet(&pslice, (), ());
799                     assert_eq!(
800                         Err(IpDefragError::UnalignedFragmentPayloadLen {
801                             offset: IpFragOffset::try_new(1).unwrap(),
802                             payload_len: 9
803                         }),
804                         v
805                     );
806 
807                     // check the frag id was correctly calculated
808                     assert_eq!(1, pool.active.len());
809                     {
810                         let p = pool.active.iter().next().unwrap();
811                         assert_eq!(p.0, &frag_id);
812                         assert_eq!(p.1 .0.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
813                         assert_eq!(p.1 .0.sections()[0].start, 0);
814                         assert_eq!(p.1 .0.sections()[0].end, 8);
815                     }
816                 }
817             }
818         }
819     }
820 
821     #[test]
retain()822     fn retain() {
823         let frag_id_0 = IpFragId {
824             outer_vlan_id: None,
825             inner_vlan_id: None,
826             ip: IpFragVersionSpecId::Ipv4 {
827                 source: [1, 2, 3, 4],
828                 destination: [5, 6, 7, 8],
829                 identification: 0,
830             },
831             payload_ip_number: IpNumber::UDP,
832             channel_id: (),
833         };
834         let frag_id_1 = IpFragId {
835             outer_vlan_id: None,
836             inner_vlan_id: None,
837             ip: IpFragVersionSpecId::Ipv4 {
838                 source: [1, 2, 3, 4],
839                 destination: [5, 6, 7, 8],
840                 identification: 1,
841             },
842             payload_ip_number: IpNumber::UDP,
843             channel_id: (),
844         };
845 
846         let mut pool = IpDefragPool::<u32, ()>::new();
847 
848         // packet timestamp 1
849         {
850             let pdata = build_packet(frag_id_0.clone(), 0, true, &[1, 2, 3, 4, 5, 6, 7, 8]);
851             let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
852             let v = pool.process_sliced_packet(&pslice, 1, ());
853             assert_eq!(Ok(None), v);
854         }
855         // packet timestamp 2
856         {
857             let pdata = build_packet(frag_id_1.clone(), 0, true, &[1, 2, 3, 4, 5, 6, 7, 8]);
858             let pslice = SlicedPacket::from_ethernet(&pdata).unwrap();
859             let v = pool.process_sliced_packet(&pslice, 2, ());
860             assert_eq!(Ok(None), v);
861         }
862 
863         // check buffers are active
864         assert_eq!(pool.active.len(), 2);
865         assert_eq!(pool.finished_data_bufs.len(), 0);
866         assert_eq!(pool.finished_section_bufs.len(), 0);
867 
868         // call retain without effect
869         pool.retain(|ts| *ts > 0);
870         assert_eq!(pool.active.len(), 2);
871         assert_eq!(pool.finished_data_bufs.len(), 0);
872         assert_eq!(pool.finished_section_bufs.len(), 0);
873 
874         // call retain and delete timestamp 1
875         pool.retain(|ts| *ts > 1);
876         assert_eq!(pool.active.len(), 1);
877         assert_eq!(pool.finished_data_bufs.len(), 1);
878         assert_eq!(pool.finished_section_bufs.len(), 1);
879         assert_eq!(pool.active.iter().next().unwrap().0, &frag_id_1);
880     }
881 }
882