1 use crate::*;
2 use proptest::prelude::*;
3 use proptest::*;
4 
vlan_ethertype_any() -> impl Strategy<Value = EtherType>5 pub fn vlan_ethertype_any() -> impl Strategy<Value = EtherType> {
6     prop_oneof![
7         Just(ether_type::VLAN_TAGGED_FRAME),
8         Just(ether_type::PROVIDER_BRIDGING),
9         Just(ether_type::VLAN_DOUBLE_TAGGED_FRAME),
10     ]
11 }
12 
13 prop_compose! {
14     pub fn ether_type_any()
15         (value in any::<u16>())
16         -> EtherType
17     {
18         EtherType(value)
19     }
20 }
21 
22 prop_compose! {
23     pub fn vlan_id_any()
24         (value in 0..=0b0000_1111_1111_1111u16)
25         -> VlanId
26     {
27         VlanId::try_new(value).unwrap()
28     }
29 }
30 
31 prop_compose! {
32     pub fn vlan_pcp_any()
33         (value in 0..=0b0000_0111u8)
34         -> VlanPcp
35     {
36         VlanPcp::try_new(value).unwrap()
37     }
38 }
39 
40 prop_compose! {
41     pub fn vlan_single_unknown()(
42         pcp in vlan_pcp_any(),
43         drop_eligible_indicator in any::<bool>(),
44         vlan_id in vlan_id_any(),
45         ether_type in ether_type_any().prop_filter("ether_type must be unknown",
46             |v| !ETHERNET_KNOWN_ETHER_TYPES.iter().any(|&x| v == &x)))
47         -> SingleVlanHeader
48     {
49         SingleVlanHeader {
50             pcp,
51             drop_eligible_indicator,
52             vlan_id,
53             ether_type,
54         }
55     }
56 }
57 
58 prop_compose! {
59     pub fn ipv6_flow_label_any()
60         (value in 0u32..=0b1111_11111111_11111111u32)
61         -> Ipv6FlowLabel
62     {
63         Ipv6FlowLabel::try_new(value).unwrap()
64     }
65 }
66 
67 prop_compose! {
68     pub fn ip_number_any()
69         (value in any::<u8>())
70         -> IpNumber
71     {
72         IpNumber(value)
73     }
74 }
75 
76 prop_compose! {
77     pub fn ethernet_2_with(ether_type: EtherType)(
78         source in prop::array::uniform6(any::<u8>()),
79         dest in prop::array::uniform6(any::<u8>()),
80         ether_type in proptest::strategy::Just(ether_type))
81         -> Ethernet2Header
82     {
83         Ethernet2Header {
84             source: source,
85             destination: dest,
86             ether_type: ether_type
87         }
88     }
89 }
90 
91 prop_compose! {
92     pub fn ethernet_2_any()
93         (ether_type in ether_type_any())
94         (result in ethernet_2_with(ether_type))
95         -> Ethernet2Header
96     {
97         result
98     }
99 }
100 
101 prop_compose! {
102     pub fn linux_sll_packet_type_any()
103         (value in 0..=LinuxSllPacketType::MAX_VAL)
104         -> LinuxSllPacketType
105     {
106         LinuxSllPacketType::try_from(value).unwrap()
107     }
108 }
109 
110 prop_compose! {
111     pub fn linux_sll_arphrd()
112         (index in 0..=(LinuxSllProtocolType::SUPPORTED_ARPHWD.len()-1))
113         -> ArpHardwareId
114     {
115         LinuxSllProtocolType::SUPPORTED_ARPHWD[index]
116     }
117 }
118 
119 prop_compose! {
120     pub fn linux_sll_sender_adress_any()
121         (mut sender_address in prop::collection::vec(any::<u8>(), 0..8))
122         -> (u16, [u8; 8])
123     {
124         let size = sender_address.len().try_into().unwrap();
125         sender_address.resize(8, 0);
126         let mut v: [u8; 8] = [0u8;8];
127         v.copy_from_slice(&sender_address);
128 
129         (size, v)
130     }
131 }
132 
133 prop_compose! {
134     pub fn linux_sll_any()
135         (packet_type in linux_sll_packet_type_any(),
136         arp_hrd_type in linux_sll_arphrd(),
137         (sender_address_valid_length, sender_address) in linux_sll_sender_adress_any(),
138         protocol_num in any::<u16>()
139     )
140         -> LinuxSllHeader
141     {
142         LinuxSllHeader {
143             packet_type,
144             arp_hrd_type,
145             sender_address_valid_length,
146             sender_address,
147             protocol_type: LinuxSllProtocolType::try_from((arp_hrd_type, protocol_num)).unwrap()
148         }
149     }
150 }
151 
152 pub static ETHERNET_KNOWN_ETHER_TYPES: &'static [EtherType] = &[
153     ether_type::IPV4,
154     ether_type::IPV6,
155     ether_type::VLAN_TAGGED_FRAME,
156     ether_type::PROVIDER_BRIDGING,
157     ether_type::VLAN_DOUBLE_TAGGED_FRAME,
158 ];
159 
160 prop_compose! {
161     pub fn ethernet_2_unknown()(
162         source in prop::array::uniform6(any::<u8>()),
163         dest in prop::array::uniform6(any::<u8>()),
164         ether_type in ether_type_any().prop_filter("ether_type must be unknown",
165             |v| !ETHERNET_KNOWN_ETHER_TYPES.iter().any(|&x| v == &x)))
166         -> Ethernet2Header
167     {
168         Ethernet2Header {
169             source: source,
170             destination: dest,
171             ether_type: ether_type
172         }
173     }
174 }
175 
176 prop_compose! {
177     pub fn vlan_single_with(ether_type: EtherType)(
178         pcp in vlan_pcp_any(),
179         drop_eligible_indicator in any::<bool>(),
180         vlan_id in vlan_id_any(),
181         ether_type in proptest::strategy::Just(ether_type))
182         -> SingleVlanHeader
183     {
184         SingleVlanHeader {
185             pcp,
186             drop_eligible_indicator,
187             vlan_id,
188             ether_type,
189         }
190     }
191 }
192 
193 prop_compose! {
194     pub fn vlan_single_any()
195         (ether_type in ether_type_any())
196         (result in vlan_single_with(ether_type))
197         -> SingleVlanHeader
198     {
199         result
200     }
201 }
202 
203 prop_compose! {
204     pub fn vlan_double_any()
205         (ether_type in ether_type_any())
206         (result in vlan_double_with(ether_type))
207         -> DoubleVlanHeader
208     {
209         result
210     }
211 }
212 
213 prop_compose! {
214     pub fn vlan_double_with(ether_type: EtherType)(
215         outer_ethertype in vlan_ethertype_any(),
216         inner_ethertype in proptest::strategy::Just(ether_type)
217     )(
218         outer in vlan_single_with(outer_ethertype),
219         inner in vlan_single_with(inner_ethertype)
220     ) -> DoubleVlanHeader {
221         DoubleVlanHeader {
222             outer,
223             inner
224         }
225     }
226 }
227 
228 prop_compose! {
229     pub fn ipv4_options_any()
230     (
231         len_div_4 in 0u8..10,
232         options_part0 in prop::array::uniform32(any::<u8>()),
233         options_part1 in prop::array::uniform8(any::<u8>())
234     ) -> Ipv4Options
235     {
236         let mut options: [u8;40] = [0;40];
237         //copy together 40 bytes of random data (the limit for static arrays in proptest 32,
238         //so a 32 & 8 byte array get combined here)
239         let len = usize::from(len_div_4)*4;
240         if len > 0 {
241             let sub_len = std::cmp::min(len,32);
242             options[..sub_len].copy_from_slice(&options_part0[..sub_len]);
243         }
244         if len > 32 {
245             let sub_len = len - 32;
246             options[32..len].copy_from_slice(&options_part1[..sub_len]);
247         }
248 
249         //set the options
250         (&options[..len]).try_into().unwrap()
251     }
252 }
253 
254 prop_compose! {
255     pub fn ipv4_with(protocol: IpNumber)
256     (
257         protocol in proptest::strategy::Just(protocol),
258         options in ipv4_options_any()
259     )(
260         source in prop::array::uniform4(any::<u8>()),
261         destination in prop::array::uniform4(any::<u8>()),
262         dscp in 0u8..=0b0011_1111,
263         ecn in 0u8..=0b0000_0011,
264         identification in any::<u16>(),
265         time_to_live in any::<u8>(),
266         dont_fragment in any::<bool>(),
267         more_fragments in any::<bool>(),
268         fragment_offset in prop::bits::u16::between(0, 13),
269         header_checksum in any::<u16>(),
270         total_len in ((Ipv4Header::MIN_LEN + usize::from(options.len())) as u16)..core::u16::MAX,
271         protocol in proptest::strategy::Just(protocol),
272         options in proptest::strategy::Just(options)
273     ) -> Ipv4Header
274     {
275         Ipv4Header{
276             dscp: dscp.try_into().unwrap(),
277             ecn: ecn.try_into().unwrap(),
278             total_len,
279             identification,
280             dont_fragment,
281             more_fragments,
282             fragment_offset: fragment_offset.try_into().unwrap(),
283             time_to_live,
284             protocol,
285             header_checksum,
286             source,
287             destination,
288             options
289         }
290     }
291 }
292 prop_compose! {
293     pub fn ipv4_any()
294                (protocol in ip_number_any())
295                (result in ipv4_with(protocol))
296                -> Ipv4Header
297     {
298         result
299     }
300 }
301 
302 static IPV4_KNOWN_PROTOCOLS: &[IpNumber] = &[
303     ip_number::ICMP,
304     ip_number::UDP,
305     ip_number::TCP,
306     ip_number::AUTH,
307     ip_number::IPV6_ICMP,
308 ];
309 
310 prop_compose! {
311     pub fn ipv4_unknown()
312         (protocol in ip_number_any().prop_filter("protocol must be unknown",
313             |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x))
314         )
315         (header in ipv4_with(protocol)
316     ) -> Ipv4Header
317     {
318         header
319     }
320 }
321 
322 prop_compose! {
323     pub fn ipv4_extensions_with(next_header: IpNumber)
324     (
325         has_auth in any::<bool>(),
326         auth in ip_auth_with(next_header)
327     ) -> Ipv4Extensions
328     {
329         if has_auth {
330             Ipv4Extensions{
331                 auth: Some(auth),
332             }
333         } else {
334             Ipv4Extensions{
335                 auth: None,
336             }
337         }
338     }
339 }
340 
341 prop_compose! {
342     pub fn ipv4_extensions_any()
343                (protocol in ip_number_any())
344                (result in ipv4_extensions_with(protocol))
345                -> Ipv4Extensions
346     {
347         result
348     }
349 }
350 
351 prop_compose! {
352     pub fn ipv4_extensions_unknown()
353         (
354             next_header in ip_number_any().prop_filter(
355                 "next_header must be unknown",
356                 |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x)
357             )
358         ) (
359             result in ipv4_extensions_with(next_header)
360         ) -> Ipv4Extensions
361     {
362         result
363     }
364 }
365 
366 prop_compose! {
367     pub fn ipv6_with(next_header: IpNumber)
368     (
369         source in prop::array::uniform16(any::<u8>()),
370         dest in prop::array::uniform16(any::<u8>()),
371         traffic_class in any::<u8>(),
372         flow_label in ipv6_flow_label_any(),
373         payload_length in any::<u16>(),
374         hop_limit in any::<u8>(),
375         next_header in proptest::strategy::Just(next_header)
376     ) -> Ipv6Header
377     {
378         Ipv6Header {
379             traffic_class: traffic_class,
380             flow_label: flow_label,
381             payload_length: payload_length,
382             next_header: next_header,
383             hop_limit: hop_limit,
384             source: source,
385             destination: dest
386         }
387     }
388 }
389 
390 prop_compose! {
391     pub fn ipv6_any()
392         (next_header in ip_number_any())
393         (result in ipv6_with(next_header)
394     ) -> Ipv6Header
395     {
396         result
397     }
398 }
399 
400 static IPV6_KNOWN_NEXT_HEADERS: &[IpNumber] = &[
401     ip_number::ICMP,
402     ip_number::UDP,
403     ip_number::TCP,
404     ip_number::IPV6_HOP_BY_HOP,
405     ip_number::IPV6_ICMP,
406     ip_number::IPV6_ROUTE,
407     ip_number::IPV6_FRAG,
408     ip_number::AUTH,
409     ip_number::IPV6_DEST_OPTIONS,
410     ip_number::MOBILITY,
411     ip_number::HIP,
412     ip_number::SHIM6,
413     // currently not supported:
414     // - EncapsulatingSecurityPayload
415     // - ExperimentalAndTesting0
416     // - ExperimentalAndTesting1
417 ];
418 
419 prop_compose! {
420     pub fn ipv6_unknown()(
421         source in prop::array::uniform16(any::<u8>()),
422         destination in prop::array::uniform16(any::<u8>()),
423         traffic_class in any::<u8>(),
424         flow_label in ipv6_flow_label_any(),
425         payload_length in any::<u16>(),
426         hop_limit in any::<u8>(),
427         next_header in ip_number_any().prop_filter("next_header must be unknown",
428             |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x))
429     ) -> Ipv6Header
430     {
431         Ipv6Header {
432             traffic_class,
433             flow_label,
434             payload_length,
435             next_header,
436             hop_limit,
437             source,
438             destination,
439         }
440     }
441 }
442 
443 prop_compose! {
444     pub fn ipv6_raw_ext_with(
445         next_header: IpNumber,
446         len: u8
447     ) (
448         next_header in proptest::strategy::Just(next_header),
449         payload in proptest::collection::vec(any::<u8>(), (len as usize)*8 + 6)
450     ) -> Ipv6RawExtHeader
451     {
452         Ipv6RawExtHeader::new_raw(
453             next_header,
454             &payload[..]
455         ).unwrap()
456     }
457 }
458 
459 prop_compose! {
460     pub fn ipv6_raw_ext_any()
461         (
462             next_header in ip_number_any(),
463             len in any::<u8>()
464         ) (
465             result in ipv6_raw_ext_with(next_header, len)
466     ) -> Ipv6RawExtHeader
467     {
468         result
469     }
470 }
471 
472 prop_compose! {
473     pub fn ipv6_extensions_with(next_header: IpNumber)
474     (
475         has_hop_by_hop_options in any::<bool>(),
476         hop_by_hop_options in ipv6_raw_ext_any(),
477         has_destination_options in any::<bool>(),
478         destination_options in ipv6_raw_ext_any(),
479         has_routing in any::<bool>(),
480         routing in ipv6_raw_ext_any(),
481         has_fragment in any::<bool>(),
482         fragment in ipv6_fragment_any(),
483         has_auth in any::<bool>(),
484         auth in ip_auth_with(next_header),
485         has_final_destination_options in any::<bool>(),
486         final_destination_options in ipv6_raw_ext_any()
487     ) -> Ipv6Extensions
488     {
489         let mut result = Ipv6Extensions {
490             hop_by_hop_options: if has_hop_by_hop_options {
491                 Some(hop_by_hop_options)
492             } else {
493                 None
494             },
495             destination_options: if has_destination_options {
496                 Some(destination_options)
497             } else {
498                 None
499             },
500             routing: if has_routing {
501                 Some(
502                     Ipv6RoutingExtensions{
503                         routing,
504                         final_destination_options: if has_final_destination_options {
505                             Some(final_destination_options)
506                         } else {
507                             None
508                         }
509                     }
510                 )
511             } else {
512                 None
513             },
514             fragment: if has_fragment {
515                 Some(fragment)
516             } else {
517                 None
518             },
519             auth: if has_auth {
520                 Some(auth)
521             } else {
522                 None
523             },
524         };
525         result.set_next_headers(next_header);
526         result
527     }
528 }
529 
530 prop_compose! {
531     pub fn ipv6_extensions_any()
532         (
533             next_header in ip_number_any()
534         ) (
535             result in ipv6_extensions_with(next_header)
536     ) -> Ipv6Extensions
537     {
538         result
539     }
540 }
541 
542 prop_compose! {
543     pub fn ipv6_extensions_unknown()
544         (
545             next_header in ip_number_any().prop_filter(
546                 "next_header must be unknown",
547                 |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x)
548             )
549         ) (
550             result in ipv6_extensions_with(next_header)
551         ) -> Ipv6Extensions
552     {
553         result
554     }
555 }
556 
557 prop_compose! {
558     pub fn ipv6_fragment_with(
559         next_header: IpNumber
560     ) (
561         next_header in proptest::strategy::Just(next_header),
562         fragment_offset in 0u16..=0b0001_1111_1111_1111u16,
563         more_fragments in any::<bool>(),
564         identification in any::<u32>(),
565     ) -> Ipv6FragmentHeader
566     {
567         Ipv6FragmentHeader::new(
568             next_header,
569             fragment_offset.try_into().unwrap(),
570             more_fragments,
571             identification
572         )
573     }
574 }
575 
576 prop_compose! {
577     pub fn ipv6_fragment_any()
578         (next_header in ip_number_any())
579         (result in ipv6_fragment_with(next_header)
580     ) -> Ipv6FragmentHeader
581     {
582         result
583     }
584 }
585 
586 prop_compose! {
587     pub fn ip_auth_with(
588         next_header: IpNumber
589     ) (
590         next_header in proptest::strategy::Just(next_header),
591         len in 1..0xffu8
592     ) (
593         next_header in proptest::strategy::Just(next_header),
594         spi in any::<u32>(),
595         sequence_number in any::<u32>(),
596         icv in proptest::collection::vec(any::<u8>(), (len as usize)*4)
597     ) -> IpAuthHeader {
598         IpAuthHeader::new(
599             next_header,
600             spi,
601             sequence_number,
602             &icv
603         ).unwrap()
604     }
605 }
606 
607 prop_compose! {
608     pub fn ip_auth_any() (
609         next_header in ip_number_any()
610     ) (
611         header in ip_auth_with(next_header)
612     ) -> IpAuthHeader {
613         header
614     }
615 }
616 
617 prop_compose! {
618     pub fn udp_any()(
619             source_port in any::<u16>(),
620             destination_port in any::<u16>(),
621             length in any::<u16>(),
622             checksum in any::<u16>())
623         -> UdpHeader
624     {
625         UdpHeader {
626             source_port: source_port,
627             destination_port: destination_port,
628             length: length,
629             checksum: checksum
630         }
631     }
632 }
633 
634 prop_compose! {
635     pub fn tcp_any()
636         (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1))
637         (
638             source_port in any::<u16>(),
639             destination_port in any::<u16>(),
640             sequence_number in any::<u32>(),
641             acknowledgment_number in any::<u32>(),
642             ns in any::<bool>(),
643             fin in any::<bool>(),
644             syn in any::<bool>(),
645             rst in any::<bool>(),
646             psh in any::<bool>(),
647             ack in any::<bool>(),
648             ece in any::<bool>(),
649             urg in any::<bool>(),
650             cwr  in any::<bool>(),
651             window_size in any::<u16>(),
652             checksum in any::<u16>(),
653             urgent_pointer in any::<u16>(),
654             options in proptest::collection::vec(any::<u8>(), ((data_offset - 5) as usize)*4))
655         -> TcpHeader
656     {
657         let mut result = TcpHeader::new(source_port, destination_port, sequence_number, window_size);
658         result.acknowledgment_number = acknowledgment_number;
659         result.ns = ns;
660         result.fin = fin;
661         result.syn = syn;
662         result.rst = rst;
663         result.psh = psh;
664         result.ack = ack;
665         result.ece = ece;
666         result.urg = urg;
667         result.cwr = cwr;
668         result.checksum = checksum;
669         result.urgent_pointer = urgent_pointer;
670         result.set_options_raw(&options[..]).unwrap();
671         result
672     }
673 }
674 
675 prop_compose! {
676     pub fn tcp_options_any()
677     (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1))
678     (
679         options in proptest::collection::vec(any::<u8>(), ((data_offset - 5) as usize)*4)
680     ) -> TcpOptions
681     {
682         TcpOptions::try_from_slice(&options).unwrap()
683     }
684 }
685 
686 prop_compose! {
687     pub fn icmpv4_type_any()
688         (
689             bytes in any::<[u8;20]>(),
690         ) -> Icmpv4Type
691     {
692         Icmpv4Header::from_slice(&bytes).unwrap().0.icmp_type
693     }
694 }
695 
696 prop_compose! {
697     pub fn icmpv4_header_any()
698         (
699             bytes in any::<[u8;20]>(),
700         ) -> Icmpv4Header
701     {
702         Icmpv4Header::from_slice(&bytes).unwrap().0
703     }
704 }
705 
706 prop_compose! {
707     pub fn icmpv6_type_any()
708         (
709             bytes in any::<[u8;8]>(),
710         ) -> Icmpv6Type
711     {
712         Icmpv6Header::from_slice(&bytes).unwrap().0.icmp_type
713     }
714 }
715 
716 prop_compose! {
717     pub fn icmpv6_header_any()
718         (
719             bytes in any::<[u8;8]>(),
720         ) -> Icmpv6Header
721     {
722         Icmpv6Header::from_slice(&bytes).unwrap().0
723     }
724 }
725