fuzz_util/
packet_formats.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Arbitrary packet generators.
6
7use arbitrary::{Arbitrary, Result, Unstructured};
8use net_types::ethernet::Mac;
9use net_types::ip::{IpAddress, Ipv4Addr};
10use packet_formats::ethernet::{EtherType, EthernetFrameBuilder, EthernetFrameLengthCheck};
11use packet_formats::icmp::IcmpParseArgs;
12use packet_formats::ip::FragmentOffset;
13use packet_formats::ipv4::Ipv4PacketBuilder;
14use packet_formats::ipv6::Ipv6PacketBuilder;
15use packet_formats::tcp::TcpParseArgs;
16use packet_formats::udp::UdpParseArgs;
17use zerocopy::FromBytes;
18
19use crate::zerocopy::ArbitraryFromBytes;
20use crate::Fuzzed;
21
22impl<'a> Arbitrary<'a> for Fuzzed<EtherType> {
23    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
24        Ok(Self(u16::arbitrary(u)?.into()))
25    }
26}
27
28impl<'a> Arbitrary<'a> for Fuzzed<EthernetFrameLengthCheck> {
29    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
30        const CHOICES: [EthernetFrameLengthCheck; 2] =
31            [EthernetFrameLengthCheck::Check, EthernetFrameLengthCheck::NoCheck];
32        // Define this with a match to ensure that CHOICES needs to be updated if
33        // EthernetFrameLengthCheck is changed.
34        u.choose(&CHOICES).map(|e| {
35            Self(match e {
36                EthernetFrameLengthCheck::Check => EthernetFrameLengthCheck::Check,
37                EthernetFrameLengthCheck::NoCheck => EthernetFrameLengthCheck::NoCheck,
38            })
39        })
40    }
41}
42
43impl<'a> Arbitrary<'a> for Fuzzed<EthernetFrameBuilder> {
44    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
45        Ok(Self(EthernetFrameBuilder::new(
46            Mac::arbitrary_from_bytes(u)?,
47            Mac::arbitrary_from_bytes(u)?,
48            Fuzzed::<EtherType>::arbitrary(u)?.into(),
49            u8::arbitrary(u)?.into(),
50        )))
51    }
52}
53
54impl<'a> Arbitrary<'a> for Fuzzed<Ipv4PacketBuilder> {
55    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
56        let src = Ipv4Addr::arbitrary_from_bytes(u)?;
57        let dst = Ipv4Addr::arbitrary_from_bytes(u)?;
58        let ttl = u.arbitrary()?;
59        let proto = u8::arbitrary(u)?.into();
60
61        let mut builder = Ipv4PacketBuilder::new(src, dst, ttl, proto);
62        builder.dscp_and_ecn(u.arbitrary::<u8>()?.into());
63        builder.df_flag(u.arbitrary()?);
64        builder.mf_flag(u.arbitrary()?);
65        builder.fragment_offset(FragmentOffset::new(u.int_in_range(0..=(1 << 13) - 1)?).unwrap());
66
67        Ok(Self(builder))
68    }
69}
70
71impl<'a> Arbitrary<'a> for Fuzzed<Ipv6PacketBuilder> {
72    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
73        let src = Ipv4Addr::arbitrary_from_bytes(u)?;
74        let dst = Ipv4Addr::arbitrary_from_bytes(u)?;
75        let ttl = u.arbitrary()?;
76        let proto = u8::arbitrary(u)?.into();
77
78        let mut builder = Ipv6PacketBuilder::new(src, dst, ttl, proto);
79        builder.dscp_and_ecn(u.arbitrary::<u8>()?.into());
80        builder.flowlabel(u.int_in_range(0..=(1 << 20 - 1))?);
81
82        Ok(Self(builder))
83    }
84}
85
86impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<IcmpParseArgs<A>> {
87    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
88        let src = A::arbitrary_from_bytes(u)?;
89        let dst = A::arbitrary_from_bytes(u)?;
90        Ok(Self(IcmpParseArgs::new(src, dst)))
91    }
92}
93
94impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<UdpParseArgs<A>> {
95    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
96        let src = A::arbitrary_from_bytes(u)?;
97        let dst = A::arbitrary_from_bytes(u)?;
98        Ok(Self(UdpParseArgs::new(src, dst)))
99    }
100}
101
102impl<'a, A: IpAddress + FromBytes> Arbitrary<'a> for Fuzzed<TcpParseArgs<A>> {
103    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
104        let src = A::arbitrary_from_bytes(u)?;
105        let dst = A::arbitrary_from_bytes(u)?;
106        Ok(Self(TcpParseArgs::new(src, dst)))
107    }
108}