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