blob: c677a3548c65b193f2928675e5f31852266d1386 [file] [log] [blame]
use crate::*;
use proptest::prelude::*;
use proptest::*;
pub fn vlan_ethertype_any() -> impl Strategy<Value = EtherType> {
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::<u16>())
-> 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::<bool>(),
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::<u8>())
-> IpNumber
{
IpNumber(value)
}
}
prop_compose! {
pub fn ethernet_2_with(ether_type: EtherType)(
source in prop::array::uniform6(any::<u8>()),
dest in prop::array::uniform6(any::<u8>()),
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::<u8>(), 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::<u16>()
)
-> 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::<u8>()),
dest in prop::array::uniform6(any::<u8>()),
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::<bool>(),
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::<u8>()),
options_part1 in prop::array::uniform8(any::<u8>())
) -> 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::<u8>()),
destination in prop::array::uniform4(any::<u8>()),
dscp in 0u8..=0b0011_1111,
ecn in 0u8..=0b0000_0011,
identification in any::<u16>(),
time_to_live in any::<u8>(),
dont_fragment in any::<bool>(),
more_fragments in any::<bool>(),
fragment_offset in prop::bits::u16::between(0, 13),
header_checksum in any::<u16>(),
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::<bool>(),
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::<u8>()),
dest in prop::array::uniform16(any::<u8>()),
traffic_class in any::<u8>(),
flow_label in ipv6_flow_label_any(),
payload_length in any::<u16>(),
hop_limit in any::<u8>(),
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::<u8>()),
destination in prop::array::uniform16(any::<u8>()),
traffic_class in any::<u8>(),
flow_label in ipv6_flow_label_any(),
payload_length in any::<u16>(),
hop_limit in any::<u8>(),
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::<u8>(), (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::<u8>()
) (
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::<bool>(),
hop_by_hop_options in ipv6_raw_ext_any(),
has_destination_options in any::<bool>(),
destination_options in ipv6_raw_ext_any(),
has_routing in any::<bool>(),
routing in ipv6_raw_ext_any(),
has_fragment in any::<bool>(),
fragment in ipv6_fragment_any(),
has_auth in any::<bool>(),
auth in ip_auth_with(next_header),
has_final_destination_options in any::<bool>(),
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::<bool>(),
identification in any::<u32>(),
) -> 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::<u32>(),
sequence_number in any::<u32>(),
icv in proptest::collection::vec(any::<u8>(), (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::<u16>(),
destination_port in any::<u16>(),
length in any::<u16>(),
checksum in any::<u16>())
-> 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::<u16>(),
destination_port in any::<u16>(),
sequence_number in any::<u32>(),
acknowledgment_number in any::<u32>(),
ns in any::<bool>(),
fin in any::<bool>(),
syn in any::<bool>(),
rst in any::<bool>(),
psh in any::<bool>(),
ack in any::<bool>(),
ece in any::<bool>(),
urg in any::<bool>(),
cwr in any::<bool>(),
window_size in any::<u16>(),
checksum in any::<u16>(),
urgent_pointer in any::<u16>(),
options in proptest::collection::vec(any::<u8>(), ((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::<u8>(), ((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
}
}