use crate::*; use proptest::prelude::*; use proptest::*; pub fn vlan_ethertype_any() -> impl Strategy { prop_oneof![ Just(ether_type::VLAN_TAGGED_FRAME), Just(ether_type::PROVIDER_BRIDGING), Just(ether_type::VLAN_DOUBLE_TAGGED_FRAME), ] } prop_compose! { pub fn ether_type_any() (value in any::()) -> EtherType { EtherType(value) } } prop_compose! { pub fn vlan_id_any() (value in 0..=0b0000_1111_1111_1111u16) -> VlanId { VlanId::try_new(value).unwrap() } } prop_compose! { pub fn vlan_pcp_any() (value in 0..=0b0000_0111u8) -> VlanPcp { VlanPcp::try_new(value).unwrap() } } prop_compose! { pub fn vlan_single_unknown()( pcp in vlan_pcp_any(), drop_eligible_indicator in any::(), vlan_id in vlan_id_any(), ether_type in ether_type_any().prop_filter("ether_type must be unknown", |v| !ETHERNET_KNOWN_ETHER_TYPES.iter().any(|&x| v == &x))) -> SingleVlanHeader { SingleVlanHeader { pcp, drop_eligible_indicator, vlan_id, ether_type, } } } prop_compose! { pub fn ipv6_flow_label_any() (value in 0u32..=0b1111_11111111_11111111u32) -> Ipv6FlowLabel { Ipv6FlowLabel::try_new(value).unwrap() } } prop_compose! { pub fn ip_number_any() (value in any::()) -> IpNumber { IpNumber(value) } } prop_compose! { pub fn ethernet_2_with(ether_type: EtherType)( source in prop::array::uniform6(any::()), dest in prop::array::uniform6(any::()), ether_type in proptest::strategy::Just(ether_type)) -> Ethernet2Header { Ethernet2Header { source: source, destination: dest, ether_type: ether_type } } } prop_compose! { pub fn ethernet_2_any() (ether_type in ether_type_any()) (result in ethernet_2_with(ether_type)) -> Ethernet2Header { result } } prop_compose! { pub fn linux_sll_packet_type_any() (value in 0..=LinuxSllPacketType::MAX_VAL) -> LinuxSllPacketType { LinuxSllPacketType::try_from(value).unwrap() } } prop_compose! { pub fn linux_sll_arphrd() (index in 0..=(LinuxSllProtocolType::SUPPORTED_ARPHWD.len()-1)) -> ArpHardwareId { LinuxSllProtocolType::SUPPORTED_ARPHWD[index] } } prop_compose! { pub fn linux_sll_sender_adress_any() (mut sender_address in prop::collection::vec(any::(), 0..8)) -> (u16, [u8; 8]) { let size = sender_address.len().try_into().unwrap(); sender_address.resize(8, 0); let mut v: [u8; 8] = [0u8;8]; v.copy_from_slice(&sender_address); (size, v) } } prop_compose! { pub fn linux_sll_any() (packet_type in linux_sll_packet_type_any(), arp_hrd_type in linux_sll_arphrd(), (sender_address_valid_length, sender_address) in linux_sll_sender_adress_any(), protocol_num in any::() ) -> LinuxSllHeader { LinuxSllHeader { packet_type, arp_hrd_type, sender_address_valid_length, sender_address, protocol_type: LinuxSllProtocolType::try_from((arp_hrd_type, protocol_num)).unwrap() } } } pub static ETHERNET_KNOWN_ETHER_TYPES: &'static [EtherType] = &[ ether_type::IPV4, ether_type::IPV6, ether_type::VLAN_TAGGED_FRAME, ether_type::PROVIDER_BRIDGING, ether_type::VLAN_DOUBLE_TAGGED_FRAME, ]; prop_compose! { pub fn ethernet_2_unknown()( source in prop::array::uniform6(any::()), dest in prop::array::uniform6(any::()), ether_type in ether_type_any().prop_filter("ether_type must be unknown", |v| !ETHERNET_KNOWN_ETHER_TYPES.iter().any(|&x| v == &x))) -> Ethernet2Header { Ethernet2Header { source: source, destination: dest, ether_type: ether_type } } } prop_compose! { pub fn vlan_single_with(ether_type: EtherType)( pcp in vlan_pcp_any(), drop_eligible_indicator in any::(), vlan_id in vlan_id_any(), ether_type in proptest::strategy::Just(ether_type)) -> SingleVlanHeader { SingleVlanHeader { pcp, drop_eligible_indicator, vlan_id, ether_type, } } } prop_compose! { pub fn vlan_single_any() (ether_type in ether_type_any()) (result in vlan_single_with(ether_type)) -> SingleVlanHeader { result } } prop_compose! { pub fn vlan_double_any() (ether_type in ether_type_any()) (result in vlan_double_with(ether_type)) -> DoubleVlanHeader { result } } prop_compose! { pub fn vlan_double_with(ether_type: EtherType)( outer_ethertype in vlan_ethertype_any(), inner_ethertype in proptest::strategy::Just(ether_type) )( outer in vlan_single_with(outer_ethertype), inner in vlan_single_with(inner_ethertype) ) -> DoubleVlanHeader { DoubleVlanHeader { outer, inner } } } prop_compose! { pub fn ipv4_options_any() ( len_div_4 in 0u8..10, options_part0 in prop::array::uniform32(any::()), options_part1 in prop::array::uniform8(any::()) ) -> Ipv4Options { let mut options: [u8;40] = [0;40]; //copy together 40 bytes of random data (the limit for static arrays in proptest 32, //so a 32 & 8 byte array get combined here) let len = usize::from(len_div_4)*4; if len > 0 { let sub_len = std::cmp::min(len,32); options[..sub_len].copy_from_slice(&options_part0[..sub_len]); } if len > 32 { let sub_len = len - 32; options[32..len].copy_from_slice(&options_part1[..sub_len]); } //set the options (&options[..len]).try_into().unwrap() } } prop_compose! { pub fn ipv4_with(protocol: IpNumber) ( protocol in proptest::strategy::Just(protocol), options in ipv4_options_any() )( source in prop::array::uniform4(any::()), destination in prop::array::uniform4(any::()), dscp in 0u8..=0b0011_1111, ecn in 0u8..=0b0000_0011, identification in any::(), time_to_live in any::(), dont_fragment in any::(), more_fragments in any::(), fragment_offset in prop::bits::u16::between(0, 13), header_checksum in any::(), total_len in ((Ipv4Header::MIN_LEN + usize::from(options.len())) as u16)..core::u16::MAX, protocol in proptest::strategy::Just(protocol), options in proptest::strategy::Just(options) ) -> Ipv4Header { Ipv4Header{ dscp: dscp.try_into().unwrap(), ecn: ecn.try_into().unwrap(), total_len, identification, dont_fragment, more_fragments, fragment_offset: fragment_offset.try_into().unwrap(), time_to_live, protocol, header_checksum, source, destination, options } } } prop_compose! { pub fn ipv4_any() (protocol in ip_number_any()) (result in ipv4_with(protocol)) -> Ipv4Header { result } } static IPV4_KNOWN_PROTOCOLS: &[IpNumber] = &[ ip_number::ICMP, ip_number::UDP, ip_number::TCP, ip_number::AUTH, ip_number::IPV6_ICMP, ]; prop_compose! { pub fn ipv4_unknown() (protocol in ip_number_any().prop_filter("protocol must be unknown", |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x)) ) (header in ipv4_with(protocol) ) -> Ipv4Header { header } } prop_compose! { pub fn ipv4_extensions_with(next_header: IpNumber) ( has_auth in any::(), auth in ip_auth_with(next_header) ) -> Ipv4Extensions { if has_auth { Ipv4Extensions{ auth: Some(auth), } } else { Ipv4Extensions{ auth: None, } } } } prop_compose! { pub fn ipv4_extensions_any() (protocol in ip_number_any()) (result in ipv4_extensions_with(protocol)) -> Ipv4Extensions { result } } prop_compose! { pub fn ipv4_extensions_unknown() ( next_header in ip_number_any().prop_filter( "next_header must be unknown", |v| !IPV4_KNOWN_PROTOCOLS.iter().any(|&x| v == &x) ) ) ( result in ipv4_extensions_with(next_header) ) -> Ipv4Extensions { result } } prop_compose! { pub fn ipv6_with(next_header: IpNumber) ( source in prop::array::uniform16(any::()), dest in prop::array::uniform16(any::()), traffic_class in any::(), flow_label in ipv6_flow_label_any(), payload_length in any::(), hop_limit in any::(), next_header in proptest::strategy::Just(next_header) ) -> Ipv6Header { Ipv6Header { traffic_class: traffic_class, flow_label: flow_label, payload_length: payload_length, next_header: next_header, hop_limit: hop_limit, source: source, destination: dest } } } prop_compose! { pub fn ipv6_any() (next_header in ip_number_any()) (result in ipv6_with(next_header) ) -> Ipv6Header { result } } static IPV6_KNOWN_NEXT_HEADERS: &[IpNumber] = &[ ip_number::ICMP, ip_number::UDP, ip_number::TCP, ip_number::IPV6_HOP_BY_HOP, ip_number::IPV6_ICMP, ip_number::IPV6_ROUTE, ip_number::IPV6_FRAG, ip_number::AUTH, ip_number::IPV6_DEST_OPTIONS, ip_number::MOBILITY, ip_number::HIP, ip_number::SHIM6, // currently not supported: // - EncapsulatingSecurityPayload // - ExperimentalAndTesting0 // - ExperimentalAndTesting1 ]; prop_compose! { pub fn ipv6_unknown()( source in prop::array::uniform16(any::()), destination in prop::array::uniform16(any::()), traffic_class in any::(), flow_label in ipv6_flow_label_any(), payload_length in any::(), hop_limit in any::(), next_header in ip_number_any().prop_filter("next_header must be unknown", |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x)) ) -> Ipv6Header { Ipv6Header { traffic_class, flow_label, payload_length, next_header, hop_limit, source, destination, } } } prop_compose! { pub fn ipv6_raw_ext_with( next_header: IpNumber, len: u8 ) ( next_header in proptest::strategy::Just(next_header), payload in proptest::collection::vec(any::(), (len as usize)*8 + 6) ) -> Ipv6RawExtHeader { Ipv6RawExtHeader::new_raw( next_header, &payload[..] ).unwrap() } } prop_compose! { pub fn ipv6_raw_ext_any() ( next_header in ip_number_any(), len in any::() ) ( result in ipv6_raw_ext_with(next_header, len) ) -> Ipv6RawExtHeader { result } } prop_compose! { pub fn ipv6_extensions_with(next_header: IpNumber) ( has_hop_by_hop_options in any::(), hop_by_hop_options in ipv6_raw_ext_any(), has_destination_options in any::(), destination_options in ipv6_raw_ext_any(), has_routing in any::(), routing in ipv6_raw_ext_any(), has_fragment in any::(), fragment in ipv6_fragment_any(), has_auth in any::(), auth in ip_auth_with(next_header), has_final_destination_options in any::(), final_destination_options in ipv6_raw_ext_any() ) -> Ipv6Extensions { let mut result = Ipv6Extensions { hop_by_hop_options: if has_hop_by_hop_options { Some(hop_by_hop_options) } else { None }, destination_options: if has_destination_options { Some(destination_options) } else { None }, routing: if has_routing { Some( Ipv6RoutingExtensions{ routing, final_destination_options: if has_final_destination_options { Some(final_destination_options) } else { None } } ) } else { None }, fragment: if has_fragment { Some(fragment) } else { None }, auth: if has_auth { Some(auth) } else { None }, }; result.set_next_headers(next_header); result } } prop_compose! { pub fn ipv6_extensions_any() ( next_header in ip_number_any() ) ( result in ipv6_extensions_with(next_header) ) -> Ipv6Extensions { result } } prop_compose! { pub fn ipv6_extensions_unknown() ( next_header in ip_number_any().prop_filter( "next_header must be unknown", |v| !IPV6_KNOWN_NEXT_HEADERS.iter().any(|&x| v == &x) ) ) ( result in ipv6_extensions_with(next_header) ) -> Ipv6Extensions { result } } prop_compose! { pub fn ipv6_fragment_with( next_header: IpNumber ) ( next_header in proptest::strategy::Just(next_header), fragment_offset in 0u16..=0b0001_1111_1111_1111u16, more_fragments in any::(), identification in any::(), ) -> Ipv6FragmentHeader { Ipv6FragmentHeader::new( next_header, fragment_offset.try_into().unwrap(), more_fragments, identification ) } } prop_compose! { pub fn ipv6_fragment_any() (next_header in ip_number_any()) (result in ipv6_fragment_with(next_header) ) -> Ipv6FragmentHeader { result } } prop_compose! { pub fn ip_auth_with( next_header: IpNumber ) ( next_header in proptest::strategy::Just(next_header), len in 1..0xffu8 ) ( next_header in proptest::strategy::Just(next_header), spi in any::(), sequence_number in any::(), icv in proptest::collection::vec(any::(), (len as usize)*4) ) -> IpAuthHeader { IpAuthHeader::new( next_header, spi, sequence_number, &icv ).unwrap() } } prop_compose! { pub fn ip_auth_any() ( next_header in ip_number_any() ) ( header in ip_auth_with(next_header) ) -> IpAuthHeader { header } } prop_compose! { pub fn udp_any()( source_port in any::(), destination_port in any::(), length in any::(), checksum in any::()) -> UdpHeader { UdpHeader { source_port: source_port, destination_port: destination_port, length: length, checksum: checksum } } } prop_compose! { pub fn tcp_any() (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1)) ( source_port in any::(), destination_port in any::(), sequence_number in any::(), acknowledgment_number in any::(), ns in any::(), fin in any::(), syn in any::(), rst in any::(), psh in any::(), ack in any::(), ece in any::(), urg in any::(), cwr in any::(), window_size in any::(), checksum in any::(), urgent_pointer in any::(), options in proptest::collection::vec(any::(), ((data_offset - 5) as usize)*4)) -> TcpHeader { let mut result = TcpHeader::new(source_port, destination_port, sequence_number, window_size); result.acknowledgment_number = acknowledgment_number; result.ns = ns; result.fin = fin; result.syn = syn; result.rst = rst; result.psh = psh; result.ack = ack; result.ece = ece; result.urg = urg; result.cwr = cwr; result.checksum = checksum; result.urgent_pointer = urgent_pointer; result.set_options_raw(&options[..]).unwrap(); result } } prop_compose! { pub fn tcp_options_any() (data_offset in TcpHeader::MIN_DATA_OFFSET..(TcpHeader::MAX_DATA_OFFSET + 1)) ( options in proptest::collection::vec(any::(), ((data_offset - 5) as usize)*4) ) -> TcpOptions { TcpOptions::try_from_slice(&options).unwrap() } } prop_compose! { pub fn icmpv4_type_any() ( bytes in any::<[u8;20]>(), ) -> Icmpv4Type { Icmpv4Header::from_slice(&bytes).unwrap().0.icmp_type } } prop_compose! { pub fn icmpv4_header_any() ( bytes in any::<[u8;20]>(), ) -> Icmpv4Header { Icmpv4Header::from_slice(&bytes).unwrap().0 } } prop_compose! { pub fn icmpv6_type_any() ( bytes in any::<[u8;8]>(), ) -> Icmpv6Type { Icmpv6Header::from_slice(&bytes).unwrap().0.icmp_type } } prop_compose! { pub fn icmpv6_header_any() ( bytes in any::<[u8;8]>(), ) -> Icmpv6Header { Icmpv6Header::from_slice(&bytes).unwrap().0 } }