curl-fuzzer C++ reference
Loading...
Searching...
No Matches
telnet_scenario.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al.
3 *
4 * SPDX-License-Identifier: curl
5 */
6
9
11
12#include <cstddef>
13#include <string>
14
16
17namespace proto_fuzzer {
18
19namespace {
20
22template <typename RepeatedField>
23void TrimRepeated(RepeatedField* field, std::size_t limit) {
24 const std::size_t size = static_cast<std::size_t>(field->size());
25 if (size > limit) {
26 field->DeleteSubrange(static_cast<int>(limit), static_cast<int>(size - limit));
27 }
28}
29
33bool BoundTelnetFragment(std::string* fragment, std::size_t* bytes_left, std::size_t* controls_left) {
34 std::size_t retained = 0;
35 while (retained < fragment->size() && retained < *bytes_left) {
36 if (static_cast<unsigned char>((*fragment)[retained]) == 0xff) {
37 if (*controls_left == 0) {
38 break;
39 }
40 --*controls_left;
41 }
42 ++retained;
43 }
44
45 const bool complete = retained == fragment->size();
46 fragment->resize(retained);
47 *bytes_left -= retained;
48 return complete;
49}
50
51} // namespace
52
62void BoundTelnetResponse(curl::fuzzer::proto::Connection* connection) {
63 if (connection == nullptr) {
64 return;
65 }
66
67 TrimRepeated(connection->mutable_on_readable(), scenario_limits::kMaxTelnetResponseChunks);
68
69 std::size_t bytes_left = scenario_limits::kMaxTelnetResponseBytes;
70 std::size_t controls_left = scenario_limits::kMaxTelnetControlBytes;
71 if (!BoundTelnetFragment(connection->mutable_initial_response(), &bytes_left, &controls_left)) {
72 connection->clear_on_readable();
73 return;
74 }
75
76 int retained_chunks = 0;
77 for (; retained_chunks < connection->on_readable_size(); ++retained_chunks) {
78 std::string* fragment = connection->mutable_on_readable(retained_chunks);
79 if (!BoundTelnetFragment(fragment, &bytes_left, &controls_left)) {
80 // A genuinely partial prefix is observable and worth retaining. When a
81 // previous fragment exhausted the budget, however, keeping the empty
82 // truncation would give LPM a field curl can never distinguish.
83 if (!fragment->empty()) {
84 ++retained_chunks;
85 }
86 break;
87 }
88 }
89
90 auto* chunks = connection->mutable_on_readable();
91 if (retained_chunks < chunks->size()) {
92 chunks->DeleteSubrange(retained_chunks, chunks->size() - retained_chunks);
93 }
94}
95
96} // namespace proto_fuzzer
Shared complexity limits for structured scenarios.
constexpr std::size_t kMaxTelnetControlBytes
Bound reply amplification as well as input bytes.
constexpr std::size_t kMaxTelnetResponseBytes
TELNET consumes the peer synchronously, so only this bounded prefix can be preloaded before curl ente...
constexpr std::size_t kMaxTelnetResponseChunks
Raw fragments are all preloaded before TELNET starts.
void BoundTelnetResponse(curl::fuzzer::proto::Connection *connection)
Retain the response prefix that TelnetMockServer can preload safely.
Shared TELNET response normalization.