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