curl-fuzzer C++ reference
Loading...
Searching...
No Matches
proxy_option_mock_server.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 <curl/curl.h>
13
14#include <algorithm>
15#include <cstddef>
16#include <cstdlib>
17#include <memory>
18#include <string>
19
20namespace proto_fuzzer {
21
22namespace {
23
24constexpr char kHostnameNoProxy[] = "not-proxy.test, .proxy.test.";
25constexpr char kIpv4NoProxy[] = "192.0.2.0/24, 127.0.0.0/8";
26constexpr char kIpv6NoProxy[] = "2001:db8::/32, ::1/128";
27constexpr char kEnvironmentProxy[] = "http://127.0.0.1:8080";
28constexpr char kLoopbackInterface[] = "host!127.0.0.1";
29
30} // namespace
31
34ProxyOptionMockServer::ProxyOptionMockServer(curl::fuzzer::proto::ProxySocketOptionMode mode)
35 : mode_(mode), setup_ok_(true), proxy_environment_active_(false), saved_http_proxy_was_set_(false) {}
36
39
45 client_transcript_.clear();
46 setup_ok_ = true;
47
48 CURLcode result = CURLE_OK;
49 switch (mode_) {
50 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_HOSTNAME:
51 result = curl_easy_setopt(easy, CURLOPT_NOPROXY, kHostnameNoProxy);
52 break;
53 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV4_CIDR:
54 result = curl_easy_setopt(easy, CURLOPT_NOPROXY, kIpv4NoProxy);
55 break;
56 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_NOPROXY_IPV6_CIDR:
57 result = curl_easy_setopt(easy, CURLOPT_NOPROXY, kIpv6NoProxy);
58 break;
59 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_ENV_HTTP_PROXY:
60 setup_ok_ = BeginProxyEnvironment();
61 if (setup_ok_) {
62 result = curl_easy_setopt(easy, CURLOPT_CONNECT_TO, nullptr);
63 }
64 if (result == CURLE_OK) {
65 result = curl_easy_setopt(easy, CURLOPT_NOPROXY, "");
66 }
67 if (result == CURLE_OK) {
68 result = curl_easy_setopt(easy, CURLOPT_PROXY, nullptr);
69 }
70 break;
71 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_DEFAULT:
72 case curl::fuzzer::proto::PROXY_SOCKET_OPTION_LOOPBACK_INTERFACE_KEEPALIVE:
73 default:
74 break;
75 }
76 setup_ok_ = setup_ok_ && result == CURLE_OK;
77}
78
80const std::string& ProxyOptionMockServer::client_transcript() const { return client_transcript_; }
81
84std::unique_ptr<MockConnection> ProxyOptionMockServer::CreateConnection() {
85 auto connection = std::make_unique<MockConnection>();
86 connection->SetIncomingDataObserver(this);
87 return connection;
88}
89
93void ProxyOptionMockServer::ObserveIncomingData(const unsigned char* data, std::size_t size) {
94 if (data == nullptr || size == 0 || client_transcript_.size() >= kMaxTranscriptBytes) {
95 return;
96 }
97 const std::size_t remaining = kMaxTranscriptBytes - client_transcript_.size();
98 client_transcript_.append(reinterpret_cast<const char*>(data), std::min(size, remaining));
99}
100
105void ProxyOptionMockServer::RunLoop(CURLM* multi, CURL* easy, const curl::fuzzer::proto::Scenario& scenario) {
106 if (setup_ok_) {
107 MockServer::RunLoop(multi, easy, scenario);
108 }
109}
110
115bool ProxyOptionMockServer::BeginProxyEnvironment() {
116 if (proxy_environment_active_) {
117 return true;
118 }
119 saved_http_proxy_.clear();
120 const char* current = std::getenv("http_proxy");
121 saved_http_proxy_was_set_ = current != nullptr;
122 if (current != nullptr) {
123 saved_http_proxy_.assign(current);
124 }
125 proxy_environment_active_ = true;
126 if (setenv("http_proxy", kEnvironmentProxy, 1) != 0) {
127 EndProxyEnvironment();
128 return false;
129 }
130 return true;
131}
132
134void ProxyOptionMockServer::EndProxyEnvironment() {
135 if (!proxy_environment_active_) {
136 return;
137 }
138 if (saved_http_proxy_was_set_) {
139 (void)setenv("http_proxy", saved_http_proxy_.c_str(), 1);
140 } else {
141 (void)unsetenv("http_proxy");
142 }
143 saved_http_proxy_.clear();
144 saved_http_proxy_was_set_ = false;
145 proxy_environment_active_ = false;
146}
147
153 (void)curl_easy_setopt(easy, CURLOPT_CONNECT_TO, nullptr);
154 (void)curl_easy_setopt(easy, CURLOPT_INTERFACE, kLoopbackInterface);
155 (void)curl_easy_setopt(easy, CURLOPT_TCP_KEEPALIVE, 1L);
156 (void)curl_easy_setopt(easy, CURLOPT_TCP_KEEPIDLE, 1L);
157 (void)curl_easy_setopt(easy, CURLOPT_TCP_KEEPINTVL, 1L);
158 (void)curl_easy_setopt(easy, CURLOPT_TCP_KEEPCNT, 1L);
159}
160
163#if defined(PROTO_FUZZER_OBSERVE_STATE)
165 const volatile std::size_t option_observation = client_transcript().size();
166 (void)option_observation;
167#endif
168}
169
170} // namespace proto_fuzzer
void Install(CURL *easy) override
Install the shared socket callbacks and remember the easy handle for the later resolve/port/timeout s...
void Install(CURL *easy) override
Install the inherited owned loopback TCP listener, then require curl to perform its normal INET setup...
virtual void Install(CURL *easy)
Install the common OPENSOCKETFUNCTION / OPENSOCKETDATA / SOCKOPTFUNCTION callbacks on 'easy'.
virtual void ObserveState()
Default no-op for peers without protocol-specific observations.
void RunLoop(CURLM *multi, CURL *easy, const curl::fuzzer::proto::Scenario &scenario) override
Seed the mock from the scenario, then drive the perform loop until curl is done or a deterministic op...
ProxyOptionMockServer(curl::fuzzer::proto::ProxySocketOptionMode mode)
Construct an idle peer for one policy-normalized mode.
void RunLoop(CURLM *multi, CURL *easy, const curl::fuzzer::proto::Scenario &scenario) override
Refuse to perform if the scoped environment or fixed setopts failed.
void ObserveIncomingData(const unsigned char *data, std::size_t size) override
Retain a bounded request transcript for exact routing assertions.
void Install(CURL *easy) override
Install socket callbacks and one fixed routing option.
std::unique_ptr< MockConnection > CreateConnection() override
Attach the transcript observer to a fresh in-process connection.
const std::string & client_transcript() const
~ProxyOptionMockServer() override
Restore process environment after curl has released the easy handle.
void ObserveState() override
Retain protocol outcomes in coverage and introspector builds.
Closed proxy, no-proxy, interface, and TCP-option peers.