blob: b2a6afdfdfad354d547bdd708b30db56ba8260e3 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Arbitrary packet generators.
use arbitrary::{Arbitrary, Result, Unstructured};
use net_types::{
ethernet::Mac,
ip::{IpAddress, Ipv4Addr},
};
use packet_formats::{
ethernet::{EtherType, EthernetFrameBuilder, EthernetFrameLengthCheck},
icmp::IcmpParseArgs,
ipv4::Ipv4PacketBuilder,
ipv6::Ipv6PacketBuilder,
tcp::TcpParseArgs,
udp::UdpParseArgs,
};
use zerocopy::FromBytes;
use crate::{zerocopy::ArbitraryFromBytes, Fuzzed};
impl<'a> Arbitrary<'a> for Fuzzed<EtherType> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
Ok(Self(u16::arbitrary(u)?.into()))
}
}
impl<'a> Arbitrary<'a> for Fuzzed<EthernetFrameLengthCheck> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
const CHOICES: [EthernetFrameLengthCheck; 2] =
[EthernetFrameLengthCheck::Check, EthernetFrameLengthCheck::NoCheck];
// Define this with a match to ensure that CHOICES needs to be updated if
// EthernetFrameLengthCheck is changed.
u.choose(&CHOICES).map(|e| {
Self(match e {
EthernetFrameLengthCheck::Check => EthernetFrameLengthCheck::Check,
EthernetFrameLengthCheck::NoCheck => EthernetFrameLengthCheck::NoCheck,
})
})
}
}
impl<'a> Arbitrary<'a> for Fuzzed<EthernetFrameBuilder> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
Ok(Self(EthernetFrameBuilder::new(
Mac::arbitrary_from_bytes(u)?,
Mac::arbitrary_from_bytes(u)?,
Fuzzed::<EtherType>::arbitrary(u)?.into(),
u8::arbitrary(u)?.into(),
)))
}
}
impl<'a> Arbitrary<'a> for Fuzzed<Ipv4PacketBuilder> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let src = Ipv4Addr::arbitrary_from_bytes(u)?;
let dst = Ipv4Addr::arbitrary_from_bytes(u)?;
let ttl = u.arbitrary()?;
let proto = u8::arbitrary(u)?.into();
let mut builder = Ipv4PacketBuilder::new(src, dst, ttl, proto);
builder.dscp(u.int_in_range(0..=(1 << 6 - 1))?);
builder.ecn(u.int_in_range(0..=3)?);
builder.df_flag(u.arbitrary()?);
builder.mf_flag(u.arbitrary()?);
builder.fragment_offset(u.int_in_range(0..=(1 << 13) - 1)?);
Ok(Self(builder))
}
}
impl<'a> Arbitrary<'a> for Fuzzed<Ipv6PacketBuilder> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let src = Ipv4Addr::arbitrary_from_bytes(u)?;
let dst = Ipv4Addr::arbitrary_from_bytes(u)?;
let ttl = u.arbitrary()?;
let proto = u8::arbitrary(u)?.into();
let mut builder = Ipv6PacketBuilder::new(src, dst, ttl, proto);
builder.ds(u.int_in_range(0..=(1 << 6 - 1))?);
builder.ecn(u.int_in_range(0..=3)?);
builder.flowlabel(u.int_in_range(0..=(1 << 20 - 1))?);
Ok(Self(builder))
}
}
impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<IcmpParseArgs<A>> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let src = A::arbitrary_from_bytes(u)?;
let dst = A::arbitrary_from_bytes(u)?;
Ok(Self(IcmpParseArgs::new(src, dst)))
}
}
impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<UdpParseArgs<A>> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let src = A::arbitrary_from_bytes(u)?;
let dst = A::arbitrary_from_bytes(u)?;
Ok(Self(UdpParseArgs::new(src, dst)))
}
}
impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<TcpParseArgs<A>> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let src = A::arbitrary_from_bytes(u)?;
let dst = A::arbitrary_from_bytes(u)?;
Ok(Self(TcpParseArgs::new(src, dst)))
}
}