• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::ARP,
154     ether_type::IPV4,
155     ether_type::IPV6,
156     ether_type::VLAN_TAGGED_FRAME,
157     ether_type::PROVIDER_BRIDGING,
158     ether_type::VLAN_DOUBLE_TAGGED_FRAME,
159 ];
160 
161 prop_compose! {
162     pub fn ethernet_2_unknown()(
163         source in prop::array::uniform6(any::<u8>()),
164         dest in prop::array::uniform6(any::<u8>()),
165         ether_type in ether_type_any().prop_filter("ether_type must be unknown",
166             |v| !ETHERNET_KNOWN_ETHER_TYPES.iter().any(|&x| v == &x)))
167         -> Ethernet2Header
168     {
169         Ethernet2Header {
170             source: source,
171             destination: dest,
172             ether_type: ether_type
173         }
174     }
175 }
176 
177 prop_compose! {
178     pub fn vlan_single_with(ether_type: EtherType)(
179         pcp in vlan_pcp_any(),
180         drop_eligible_indicator in any::<bool>(),
181         vlan_id in vlan_id_any(),
182         ether_type in proptest::strategy::Just(ether_type))
183         -> SingleVlanHeader
184     {
185         SingleVlanHeader {
186             pcp,
187             drop_eligible_indicator,
188             vlan_id,
189             ether_type,
190         }
191     }
192 }
193 
194 prop_compose! {
195     pub fn vlan_single_any()
196         (ether_type in ether_type_any())
197         (result in vlan_single_with(ether_type))
198         -> SingleVlanHeader
199     {
200         result
201     }
202 }
203 
204 prop_compose! {
205     pub fn vlan_double_any()
206         (ether_type in ether_type_any())
207         (result in vlan_double_with(ether_type))
208         -> DoubleVlanHeader
209     {
210         result
211     }
212 }
213 
214 prop_compose! {
215     pub fn vlan_double_with(ether_type: EtherType)(
216         outer_ethertype in vlan_ethertype_any(),
217         inner_ethertype in proptest::strategy::Just(ether_type)
218     )(
219         outer in vlan_single_with(outer_ethertype),
220         inner in vlan_single_with(inner_ethertype)
221     ) -> DoubleVlanHeader {
222         DoubleVlanHeader {
223             outer,
224             inner
225         }
226     }
227 }
228 
229 prop_compose! {
230     pub fn arp_packet_any()
231     (
232         hw_addr_size in any::<u8>(),
233         proto_addr_size in any::<u8>()
234     )
235     (
236         hw_addr_type in any::<u16>(),
237         proto_addr_type in any::<u16>(),
238         operation in any::<u16>(),
239         sender_hw_addr in prop::collection::vec(any::<u8>(), hw_addr_size as usize),
240         sender_protocol_addr in prop::collection::vec(any::<u8>(), proto_addr_size as usize),
241         target_hw_addr in prop::collection::vec(any::<u8>(), hw_addr_size as usize),
242         target_protocol_addr in prop::collection::vec(any::<u8>(), proto_addr_size as usize)
243     ) -> ArpPacket
244     {
245         ArpPacket::new(
246             ArpHardwareId(hw_addr_type),
247             EtherType(proto_addr_type),
248             ArpOperation(operation),
249             &sender_hw_addr[..],
250             &sender_protocol_addr[..],
251             &target_hw_addr[..],
252             &target_protocol_addr[..]
253         ).unwrap()
254     }
255 }
256 
257 prop_compose! {
258     pub fn arp_eth_ipv4_packet_any()
259     (
260         operation in any::<u16>(),
261         sender_mac in prop::array::uniform6(any::<u8>()),
262         sender_ipv4 in prop::array::uniform4(any::<u8>()),
263         target_mac in prop::array::uniform6(any::<u8>()),
264         target_ipv4 in prop::array::uniform4(any::<u8>())
265     ) -> ArpEthIpv4Packet
266     {
267         ArpEthIpv4Packet {
268             operation: ArpOperation(operation),
269             sender_mac,
270             sender_ipv4,
271             target_mac,
272             target_ipv4,
273         }
274     }
275 }
276 
277 prop_compose! {
278     pub fn ipv4_options_any()
279     (
280         len_div_4 in 0u8..10,
281         options_part0 in prop::array::uniform32(any::<u8>()),
282         options_part1 in prop::array::uniform8(any::<u8>())
283     ) -> Ipv4Options
284     {
285         let mut options: [u8;40] = [0;40];
286         //copy together 40 bytes of random data (the limit for static arrays in proptest 32,
287         //so a 32 & 8 byte array get combined here)
288         let len = usize::from(len_div_4)*4;
289         if len > 0 {
290             let sub_len = std::cmp::min(len,32);
291             options[..sub_len].copy_from_slice(&options_part0[..sub_len]);
292         }
293         if len > 32 {
294             let sub_len = len - 32;
295             options[32..len].copy_from_slice(&options_part1[..sub_len]);
296         }
297 
298         //set the options
299         (&options[..len]).try_into().unwrap()
300     }
301 }
302 
303 prop_compose! {
304     pub fn ipv4_with(protocol: IpNumber)
305     (
306         protocol in proptest::strategy::Just(protocol),
307         options in ipv4_options_any()
308     )(
309         source in prop::array::uniform4(any::<u8>()),
310         destination in prop::array::uniform4(any::<u8>()),
311         dscp in 0u8..=0b0011_1111,
312         ecn in 0u8..=0b0000_0011,
313         identification in any::<u16>(),
314         time_to_live in any::<u8>(),
315         dont_fragment in any::<bool>(),
316         more_fragments in any::<bool>(),
317         fragment_offset in prop::bits::u16::between(0, 13),
318         header_checksum in any::<u16>(),
319         total_len in ((Ipv4Header::MIN_LEN + usize::from(options.len())) as u16)..core::u16::MAX,
320         protocol in proptest::strategy::Just(protocol),
321         options in proptest::strategy::Just(options)
322     ) -> Ipv4Header
323     {
324         Ipv4Header{
325             dscp: dscp.try_into().unwrap(),
326             ecn: ecn.try_into().unwrap(),
327             total_len,
328             identification,
329             dont_fragment,
330             more_fragments,
331             fragment_offset: fragment_offset.try_into().unwrap(),
332             time_to_live,
333             protocol,
334             header_checksum,
335             source,
336             destination,
337             options
338         }
339     }
340 }
341 prop_compose! {
342     pub fn ipv4_any()
343                (protocol in ip_number_any())
344                (result in ipv4_with(protocol))
345                -> Ipv4Header
346     {
347         result
348     }
349 }
350 
351 static IPV4_KNOWN_PROTOCOLS: &[IpNumber] = &[
352     ip_number::ICMP,
353     ip_number::UDP,
354     ip_number::TCP,
355     ip_number::AUTH,
356     ip_number::IPV6_ICMP,
357 ];
358 
359 prop_compose! {
360     pub fn ipv4_unknown()
361         (protocol in ip_number_any().prop_filter("protocol must be unknown",
362             |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x))
363         )
364         (header in ipv4_with(protocol)
365     ) -> Ipv4Header
366     {
367         header
368     }
369 }
370 
371 prop_compose! {
372     pub fn ipv4_extensions_with(next_header: IpNumber)
373     (
374         has_auth in any::<bool>(),
375         auth in ip_auth_with(next_header)
376     ) -> Ipv4Extensions
377     {
378         if has_auth {
379             Ipv4Extensions{
380                 auth: Some(auth),
381             }
382         } else {
383             Ipv4Extensions{
384                 auth: None,
385             }
386         }
387     }
388 }
389 
390 prop_compose! {
391     pub fn ipv4_extensions_any()
392                (protocol in ip_number_any())
393                (result in ipv4_extensions_with(protocol))
394                -> Ipv4Extensions
395     {
396         result
397     }
398 }
399 
400 prop_compose! {
401     pub fn ipv4_extensions_unknown()
402         (
403             next_header in ip_number_any().prop_filter(
404                 "next_header must be unknown",
405                 |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x)
406             )
407         ) (
408             result in ipv4_extensions_with(next_header)
409         ) -> Ipv4Extensions
410     {
411         result
412     }
413 }
414 
415 prop_compose! {
416     pub fn ipv6_with(next_header: IpNumber)
417     (
418         source in prop::array::uniform16(any::<u8>()),
419         dest in prop::array::uniform16(any::<u8>()),
420         traffic_class in any::<u8>(),
421         flow_label in ipv6_flow_label_any(),
422         payload_length in any::<u16>(),
423         hop_limit in any::<u8>(),
424         next_header in proptest::strategy::Just(next_header)
425     ) -> Ipv6Header
426     {
427         Ipv6Header {
428             traffic_class: traffic_class,
429             flow_label: flow_label,
430             payload_length: payload_length,
431             next_header: next_header,
432             hop_limit: hop_limit,
433             source: source,
434             destination: dest
435         }
436     }
437 }
438 
439 prop_compose! {
440     pub fn ipv6_any()
441         (next_header in ip_number_any())
442         (result in ipv6_with(next_header)
443     ) -> Ipv6Header
444     {
445         result
446     }
447 }
448 
449 static IPV6_KNOWN_NEXT_HEADERS: &[IpNumber] = &[
450     ip_number::ICMP,
451     ip_number::UDP,
452     ip_number::TCP,
453     ip_number::IPV6_HOP_BY_HOP,
454     ip_number::IPV6_ICMP,
455     ip_number::IPV6_ROUTE,
456     ip_number::IPV6_FRAG,
457     ip_number::AUTH,
458     ip_number::IPV6_DEST_OPTIONS,
459     ip_number::MOBILITY,
460     ip_number::HIP,
461     ip_number::SHIM6,
462     // currently not supported:
463     // - EncapsulatingSecurityPayload
464     // - ExperimentalAndTesting0
465     // - ExperimentalAndTesting1
466 ];
467 
468 prop_compose! {
469     pub fn ipv6_unknown()(
470         source in prop::array::uniform16(any::<u8>()),
471         destination in prop::array::uniform16(any::<u8>()),
472         traffic_class in any::<u8>(),
473         flow_label in ipv6_flow_label_any(),
474         payload_length in any::<u16>(),
475         hop_limit in any::<u8>(),
476         next_header in ip_number_any().prop_filter("next_header must be unknown",
477             |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x))
478     ) -> Ipv6Header
479     {
480         Ipv6Header {
481             traffic_class,
482             flow_label,
483             payload_length,
484             next_header,
485             hop_limit,
486             source,
487             destination,
488         }
489     }
490 }
491 
492 prop_compose! {
493     pub fn ipv6_raw_ext_with(
494         next_header: IpNumber,
495         len: u8
496     ) (
497         next_header in proptest::strategy::Just(next_header),
498         payload in proptest::collection::vec(any::<u8>(), (len as usize)*8 + 6)
499     ) -> Ipv6RawExtHeader
500     {
501         Ipv6RawExtHeader::new_raw(
502             next_header,
503             &payload[..]
504         ).unwrap()
505     }
506 }
507 
508 prop_compose! {
509     pub fn ipv6_raw_ext_any()
510         (
511             next_header in ip_number_any(),
512             len in any::<u8>()
513         ) (
514             result in ipv6_raw_ext_with(next_header, len)
515     ) -> Ipv6RawExtHeader
516     {
517         result
518     }
519 }
520 
521 prop_compose! {
522     pub fn ipv6_extensions_with(next_header: IpNumber)
523     (
524         has_hop_by_hop_options in any::<bool>(),
525         hop_by_hop_options in ipv6_raw_ext_any(),
526         has_destination_options in any::<bool>(),
527         destination_options in ipv6_raw_ext_any(),
528         has_routing in any::<bool>(),
529         routing in ipv6_raw_ext_any(),
530         has_fragment in any::<bool>(),
531         fragment in ipv6_fragment_any(),
532         has_auth in any::<bool>(),
533         auth in ip_auth_with(next_header),
534         has_final_destination_options in any::<bool>(),
535         final_destination_options in ipv6_raw_ext_any()
536     ) -> Ipv6Extensions
537     {
538         let mut result = Ipv6Extensions {
539             hop_by_hop_options: if has_hop_by_hop_options {
540                 Some(hop_by_hop_options)
541             } else {
542                 None
543             },
544             destination_options: if has_destination_options {
545                 Some(destination_options)
546             } else {
547                 None
548             },
549             routing: if has_routing {
550                 Some(
551                     Ipv6RoutingExtensions{
552                         routing,
553                         final_destination_options: if has_final_destination_options {
554                             Some(final_destination_options)
555                         } else {
556                             None
557                         }
558                     }
559                 )
560             } else {
561                 None
562             },
563             fragment: if has_fragment {
564                 Some(fragment)
565             } else {
566                 None
567             },
568             auth: if has_auth {
569                 Some(auth)
570             } else {
571                 None
572             },
573         };
574         result.set_next_headers(next_header);
575         result
576     }
577 }
578 
579 prop_compose! {
580     pub fn ipv6_extensions_any()
581         (
582             next_header in ip_number_any()
583         ) (
584             result in ipv6_extensions_with(next_header)
585     ) -> Ipv6Extensions
586     {
587         result
588     }
589 }
590 
591 prop_compose! {
592     pub fn ipv6_extensions_unknown()
593         (
594             next_header in ip_number_any().prop_filter(
595                 "next_header must be unknown",
596                 |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x)
597             )
598         ) (
599             result in ipv6_extensions_with(next_header)
600         ) -> Ipv6Extensions
601     {
602         result
603     }
604 }
605 
606 prop_compose! {
607     pub fn ipv6_fragment_with(
608         next_header: IpNumber
609     ) (
610         next_header in proptest::strategy::Just(next_header),
611         fragment_offset in 0u16..=0b0001_1111_1111_1111u16,
612         more_fragments in any::<bool>(),
613         identification in any::<u32>(),
614     ) -> Ipv6FragmentHeader
615     {
616         Ipv6FragmentHeader::new(
617             next_header,
618             fragment_offset.try_into().unwrap(),
619             more_fragments,
620             identification
621         )
622     }
623 }
624 
625 prop_compose! {
626     pub fn ipv6_fragment_any()
627         (next_header in ip_number_any())
628         (result in ipv6_fragment_with(next_header)
629     ) -> Ipv6FragmentHeader
630     {
631         result
632     }
633 }
634 
635 prop_compose! {
636     pub fn ip_auth_with(
637         next_header: IpNumber
638     ) (
639         next_header in proptest::strategy::Just(next_header),
640         len in 1..0xffu8
641     ) (
642         next_header in proptest::strategy::Just(next_header),
643         spi in any::<u32>(),
644         sequence_number in any::<u32>(),
645         icv in proptest::collection::vec(any::<u8>(), (len as usize)*4)
646     ) -> IpAuthHeader {
647         IpAuthHeader::new(
648             next_header,
649             spi,
650             sequence_number,
651             &icv
652         ).unwrap()
653     }
654 }
655 
656 prop_compose! {
657     pub fn ip_auth_any() (
658         next_header in ip_number_any()
659     ) (
660         header in ip_auth_with(next_header)
661     ) -> IpAuthHeader {
662         header
663     }
664 }
665 
666 prop_compose! {
667     pub fn udp_any()(
668             source_port in any::<u16>(),
669             destination_port in any::<u16>(),
670             length in any::<u16>(),
671             checksum in any::<u16>())
672         -> UdpHeader
673     {
674         UdpHeader {
675             source_port: source_port,
676             destination_port: destination_port,
677             length: length,
678             checksum: checksum
679         }
680     }
681 }
682 
683 prop_compose! {
684     pub fn tcp_any()
685         (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1))
686         (
687             source_port in any::<u16>(),
688             destination_port in any::<u16>(),
689             sequence_number in any::<u32>(),
690             acknowledgment_number in any::<u32>(),
691             ns in any::<bool>(),
692             fin in any::<bool>(),
693             syn in any::<bool>(),
694             rst in any::<bool>(),
695             psh in any::<bool>(),
696             ack in any::<bool>(),
697             ece in any::<bool>(),
698             urg in any::<bool>(),
699             cwr  in any::<bool>(),
700             window_size in any::<u16>(),
701             checksum in any::<u16>(),
702             urgent_pointer in any::<u16>(),
703             options in proptest::collection::vec(any::<u8>(), ((data_offset - 5) as usize)*4))
704         -> TcpHeader
705     {
706         let mut result = TcpHeader::new(source_port, destination_port, sequence_number, window_size);
707         result.acknowledgment_number = acknowledgment_number;
708         result.ns = ns;
709         result.fin = fin;
710         result.syn = syn;
711         result.rst = rst;
712         result.psh = psh;
713         result.ack = ack;
714         result.ece = ece;
715         result.urg = urg;
716         result.cwr = cwr;
717         result.checksum = checksum;
718         result.urgent_pointer = urgent_pointer;
719         result.set_options_raw(&options[..]).unwrap();
720         result
721     }
722 }
723 
724 prop_compose! {
725     pub fn tcp_options_any()
726     (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1))
727     (
728         options in proptest::collection::vec(any::<u8>(), ((data_offset - 5) as usize)*4)
729     ) -> TcpOptions
730     {
731         TcpOptions::try_from_slice(&options).unwrap()
732     }
733 }
734 
735 prop_compose! {
736     pub fn icmpv4_type_any()
737         (
738             bytes in any::<[u8;20]>(),
739         ) -> Icmpv4Type
740     {
741         Icmpv4Header::from_slice(&bytes).unwrap().0.icmp_type
742     }
743 }
744 
745 prop_compose! {
746     pub fn icmpv4_header_any()
747         (
748             bytes in any::<[u8;20]>(),
749         ) -> Icmpv4Header
750     {
751         Icmpv4Header::from_slice(&bytes).unwrap().0
752     }
753 }
754 
755 prop_compose! {
756     pub fn icmpv6_type_any()
757         (
758             bytes in any::<[u8;8]>(),
759         ) -> Icmpv6Type
760     {
761         Icmpv6Header::from_slice(&bytes).unwrap().0.icmp_type
762     }
763 }
764 
765 prop_compose! {
766     pub fn icmpv6_header_any()
767         (
768             bytes in any::<[u8;8]>(),
769         ) -> Icmpv6Header
770     {
771         Icmpv6Header::from_slice(&bytes).unwrap().0
772     }
773 }
774