Coverage Report

Created: 2026-05-16 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/lib/dhcpsrv/packet_fuzzer.h
Line
Count
Source
1
// Copyright (C) 2016-2024 Internet Systems Consortium, Inc. ("ISC")
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
#ifndef DHCPSRV_PACKET_FUZZER_H
8
#define DHCPSRV_PACKET_FUZZER_H
9
10
#ifdef FUZZING
11
12
#include <asiolink/io_address.h>
13
#include <exceptions/exceptions.h>
14
15
#include <arpa/inet.h>
16
#include <net/if.h>
17
#include <sys/socket.h>
18
#include <unistd.h>
19
20
#include <string>
21
22
namespace isc {
23
24
/// @brief AFL Fuzzing
25
///
26
/// Persistent-mode AFL fuzzing has the AFL fuzzer send packets of data to
27
/// stdin of the program being tested. The program processes the data and
28
/// signals to AFL that it is complete.
29
///
30
/// To reduce the code changes required, the scheme adopted for Kea is that
31
/// the AFL data read from stdin is written to an address/port on which Kea
32
/// is listening.  Kea then reads the data from that port and processes it
33
/// in the usual way.
34
///
35
/// The PacketFuzzer class handles the transfer of data between AFL and Kea.  After
36
/// suitable initialization, its transfer() method is called in the main
37
/// processing loop, right before Kea waits for input. The method handles the
38
/// read from stdin and the write to the selected address port.
39
40
class PacketFuzzer {
41
public:
42
    /// @brief size of the buffer used to transfer data between AFL and Kea.
43
    ///
44
    /// This is much larger than the data that will be sent to Kea (so AFL
45
    /// data may be trimmed).  However, it does allow for AFL to send quite
46
    /// large packets without resulting in AFL synchronization problems because
47
    /// Kea has not read all the data sent.
48
    static constexpr size_t BUFFER_SIZE = 256 * 1024;
49
50
    /// @brief maximum size of packets fuzzing thread will send to Kea
51
    ///
52
    /// This is below the maximum size of data that we will allow Kea to put
53
    /// into a single UDP datagram so as to avoid any "data too big" errors
54
    /// when trying to send it to the port on which Kea listens.
55
    static constexpr size_t MAX_SEND_SIZE = 64000;
56
57
    /// @brief Number of packets Kea will process before shutting down.
58
    ///
59
    /// After the shutdown, AFL will restart it. This safety switch is here for
60
    /// eliminating cases where Kea goes into a weird state and stops
61
    /// processing packets properly.  This can be overridden by setting the
62
    /// environment variable KEA_AFL_LOOP_MAX.
63
    static constexpr long MAX_LOOP_COUNT = 1000;
64
65
    /// @brief Constructor
66
    ///
67
    /// Sets up data structures to access the address/port being used to
68
    /// transfer data from AFL to Kea.
69
    ///
70
    /// @param port      Port on which the server is listening, and hence the
71
    ///                  port to which the fuzzer will send input from AFL.
72
    PacketFuzzer(uint16_t const port,
73
                 std::string const interface,
74
                 std::string const address);
75
76
    /// @brief Destructor
77
    ///
78
    /// Closes the socket used for transferring data from stdin to the selected
79
    /// interface.
80
    ~PacketFuzzer();
81
82
    /// @brief Transfer Data
83
    ///
84
    /// Called immediately prior to Kea reading data, this reads stdin (where
85
    /// AFL will have sent the packet being tested) and copies the data to the
86
    /// interface on which Kea is listening.
87
    void transfer() const;
88
    void transfer(uint8_t const* data, size_t size) const;
89
90
    /// @brief Return Max Loop Count
91
    ///
92
    /// Returns the maximum number of loops (i.e. AFL packets processed) before
93
    /// Kea exits.  This is the value of the environment variable
94
    /// FUZZ_AFL_LOOP_MAX, or the class constant MAX_LOOP_COUNT if that is not
95
    /// defined.
96
    ///
97
    /// @return Maximum loop count
98
0
    long maxLoopCount() const {
99
0
        return loop_max_;
100
0
    }
101
102
private:
103
    /// @brief Create address structures
104
    ///
105
    /// Create the address structures describing the address/port on whick Kea
106
    /// is listening for packets from AFL.
107
    ///
108
    /// @param port         Port to be used.
109
    /// @param interface    Interface through which the fuzzer is sending packets to Kea.
110
    /// @param io_address   Address on the interface that will be used.
111
    ///
112
    /// @throws FuzzInitFail Thrown if the address is not in the expected
113
    ///                      format.
114
    void createAddressStructures(uint16_t const port,
115
                                 std::string const& interface,
116
                                 isc::asiolink::IOAddress const& io_address);
117
118
    // Other member variables.
119
    long                loop_max_;      //< Maximum number of loop iterations
120
    size_t              sockaddr_len_;  //< Length of the structure
121
    struct sockaddr*    sockaddr_ptr_;  //< Pointer to structure used
122
    struct sockaddr_in  servaddr4_;     //< IPv6 address information
123
    struct sockaddr_in6 servaddr6_;     //< IPv6 address information
124
    int                 sockfd_;        //< Socket used to transfer data
125
};  // class PacketFuzzer
126
127
/// @brief Exception thrown if fuzzing initialization fails.
128
class FuzzInitFail : public Exception {
129
public:
130
    FuzzInitFail(const char* file, size_t line, const char* what) :
131
0
        isc::Exception(file, line, what) { }
132
};  // class FuzzInitFail
133
134
}  // namespace isc
135
136
#endif  // FUZZING
137
138
#endif  // DHCPSRV_PACKET_FUZZER_H