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;
}
|