srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/fuzz/fuzz_tcp_reassembly.cpp
blob: 26389d8b89271a17683c3ec92b2b1b556b1c7a9e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <cstddef>
#include <cstdint>

#include "packeteer/net/tcp_reassembly.hpp"

using namespace packeteer::net;

// Unlike the other fuzz harnesses, this drives *one* TcpReassembler
// with a whole sequence of segments parsed out of a single input --
// the interesting bugs here are in cross-call state (the flow map,
// per-direction sequence tracking, the buffer-size cap), not in
// decoding one segment alone. Each record is a fixed 19-byte header
// (src ip/port, dst ip/port, seq, flags, a payload length) followed by
// that many payload bytes; malformed/truncated trailing records are
// simply skipped rather than treated as an error, same as any other
// best-effort parse in this project.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    TcpReassembler reassembler;

    size_t pos = 0;
    while (pos + 19 <= size) {
        Ipv4Address src{{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}};
        Ipv4Address dst{{data[pos + 4], data[pos + 5], data[pos + 6], data[pos + 7]}};
        std::uint16_t src_port = static_cast<std::uint16_t>(data[pos + 8] << 8 | data[pos + 9]);
        std::uint16_t dst_port = static_cast<std::uint16_t>(data[pos + 10] << 8 | data[pos + 11]);
        std::uint32_t seq = static_cast<std::uint32_t>(data[pos + 12]) << 24 |
                             static_cast<std::uint32_t>(data[pos + 13]) << 16 |
                             static_cast<std::uint32_t>(data[pos + 14]) << 8 | data[pos + 15];
        std::uint8_t flags = data[pos + 16];
        std::uint16_t payload_len =
            static_cast<std::uint16_t>(data[pos + 17] << 8 | data[pos + 18]);
        pos += 19;

        std::size_t available = size - pos;
        std::size_t take = payload_len < available ? payload_len : available;
        std::span<const unsigned char> payload{data + pos, take};
        pos += take;

        reassembler.process_segment(src, src_port, dst, dst_port, seq, flags, payload);
    }
    return 0;
}