Bitcoin Core 28.99.0
P2P Digital Currency
net.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
7#include <compat/compat.h>
8#include <netaddress.h>
10#include <protocol.h>
12#include <test/fuzz/util.h>
13#include <test/util/net.h>
14#include <util/sock.h>
15#include <util/time.h>
16
17#include <array>
18#include <cassert>
19#include <cerrno>
20#include <cstdint>
21#include <cstdlib>
22#include <cstring>
23#include <thread>
24#include <vector>
25
26class CNode;
27
28CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand) noexcept
29{
30 struct NetAux {
31 Network net;
33 size_t len;
34 };
35
36 static constexpr std::array<NetAux, 6> nets{
37 NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE},
38 NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE},
39 NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE},
40 NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE},
41 NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE},
42 NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0},
43 };
44
45 const size_t nets_index{rand == nullptr
46 ? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1)
47 : static_cast<size_t>(rand->randrange(nets.size()))};
48
49 const auto& aux = nets[nets_index];
50
51 CNetAddr addr;
52
53 if (aux.net == Network::NET_INTERNAL) {
54 if (rand == nullptr) {
55 addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
56 } else {
57 const auto v = rand->randbytes(32);
58 addr.SetInternal(std::string{v.begin(), v.end()});
59 }
60 return addr;
61 }
62
64
65 s << static_cast<uint8_t>(aux.bip155);
66
67 std::vector<uint8_t> addr_bytes;
68 if (rand == nullptr) {
69 addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len);
70 addr_bytes.resize(aux.len);
71 } else {
72 addr_bytes = rand->randbytes(aux.len);
73 }
74 if (aux.net == NET_IPV6 && addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS.
75 addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do.
76 }
77 if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid().
78 addr_bytes[0] = CJDNS_PREFIX;
79 }
80 s << addr_bytes;
81
82 s >> CAddress::V2_NETWORK(addr);
83
84 return addr;
85}
86
87CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
88{
89 return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
90}
91
92template <typename P>
93P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept
94{
95 constexpr std::array ADDR_ENCODINGS{
98 };
99 constexpr std::array ADDR_FORMATS{
102 };
103 if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {
104 return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};
105 }
106 if constexpr (std::is_same_v<P, CAddress::SerParams>) {
107 return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};
108 }
109}
112
114 : Sock{fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET)},
115 m_fuzzed_data_provider{fuzzed_data_provider},
116 m_selectable{fuzzed_data_provider.ConsumeBool()}
117{
118}
119
121{
122 // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
123 // close(m_socket) if m_socket is not INVALID_SOCKET.
124 // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
125 // theoretically may concide with a real opened file descriptor).
127}
128
130{
131 assert(false && "Move of Sock into FuzzedSock not allowed.");
132 return *this;
133}
134
135ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
136{
137 constexpr std::array send_errnos{
138 EACCES,
139 EAGAIN,
140 EALREADY,
141 EBADF,
142 ECONNRESET,
143 EDESTADDRREQ,
144 EFAULT,
145 EINTR,
146 EINVAL,
147 EISCONN,
148 EMSGSIZE,
149 ENOBUFS,
150 ENOMEM,
151 ENOTCONN,
152 ENOTSOCK,
153 EOPNOTSUPP,
154 EPIPE,
155 EWOULDBLOCK,
156 };
158 return len;
159 }
160 const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
161 if (r == -1) {
163 }
164 return r;
165}
166
167ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
168{
169 // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
170 // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
171 // returning -1 and setting errno to EAGAIN repeatedly.
172 constexpr std::array recv_errnos{
173 ECONNREFUSED,
174 EAGAIN,
175 EBADF,
176 EFAULT,
177 EINTR,
178 EINVAL,
179 ENOMEM,
180 ENOTCONN,
181 ENOTSOCK,
182 EWOULDBLOCK,
183 };
184 assert(buf != nullptr || len == 0);
185
186 // Do the latency before any of the "return" statements.
187 if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
188 std::this_thread::sleep_for(std::chrono::milliseconds{2});
189 }
190
191 if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
192 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
193 if (r == -1) {
195 }
196 return r;
197 }
198
199 size_t copied_so_far{0};
200
201 if (!m_peek_data.empty()) {
202 // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
203 const size_t copy_len{std::min(len, m_peek_data.size())};
204 std::memcpy(buf, m_peek_data.data(), copy_len);
205 copied_so_far += copy_len;
206 if ((flags & MSG_PEEK) == 0) {
207 m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
208 }
209 }
210
211 if (copied_so_far == len) {
212 return copied_so_far;
213 }
214
215 auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
216 if (new_data.empty()) return copied_so_far;
217
218 std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
219 copied_so_far += new_data.size();
220
221 if ((flags & MSG_PEEK) != 0) {
222 m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
223 }
224
225 if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
226 return copied_so_far;
227 }
228
229 // Pad to len bytes.
230 std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
231
232 return len;
233}
234
235int FuzzedSock::Connect(const sockaddr*, socklen_t) const
236{
237 // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
238 // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
239 // returning -1 and setting errno to EAGAIN repeatedly.
240 constexpr std::array connect_errnos{
241 ECONNREFUSED,
242 EAGAIN,
243 ECONNRESET,
244 EHOSTUNREACH,
245 EINPROGRESS,
246 EINTR,
247 ENETUNREACH,
248 ETIMEDOUT,
249 };
251 SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
252 return -1;
253 }
254 return 0;
255}
256
257int FuzzedSock::Bind(const sockaddr*, socklen_t) const
258{
259 // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
260 // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
261 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
262 // repeatedly because proper code should retry on temporary errors, leading to an
263 // infinite loop.
264 constexpr std::array bind_errnos{
265 EACCES,
266 EADDRINUSE,
267 EADDRNOTAVAIL,
268 EAGAIN,
269 };
272 return -1;
273 }
274 return 0;
275}
276
277int FuzzedSock::Listen(int) const
278{
279 // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
280 // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
281 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
282 // repeatedly because proper code should retry on temporary errors, leading to an
283 // infinite loop.
284 constexpr std::array listen_errnos{
285 EADDRINUSE,
286 EINVAL,
287 EOPNOTSUPP,
288 };
291 return -1;
292 }
293 return 0;
294}
295
296std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
297{
298 constexpr std::array accept_errnos{
299 ECONNABORTED,
300 EINTR,
301 ENOMEM,
302 };
305 return std::unique_ptr<FuzzedSock>();
306 }
307 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
308}
309
310int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
311{
312 constexpr std::array getsockopt_errnos{
313 ENOMEM,
314 ENOBUFS,
315 };
317 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
318 return -1;
319 }
320 if (opt_val == nullptr) {
321 return 0;
322 }
323 std::memcpy(opt_val,
325 *opt_len);
326 return 0;
327}
328
329int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
330{
331 constexpr std::array setsockopt_errnos{
332 ENOMEM,
333 ENOBUFS,
334 };
336 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
337 return -1;
338 }
339 return 0;
340}
341
342int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
343{
344 constexpr std::array getsockname_errnos{
345 ECONNRESET,
346 ENOBUFS,
347 };
349 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
350 return -1;
351 }
352 *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
353 return 0;
354}
355
357{
358 constexpr std::array setnonblocking_errnos{
359 EBADF,
360 EPERM,
361 };
363 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
364 return false;
365 }
366 return true;
367}
368
370{
371 return m_selectable;
372}
373
374bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
375{
376 constexpr std::array wait_errnos{
377 EBADF,
378 EINTR,
379 EINVAL,
380 };
383 return false;
384 }
385 if (occurred != nullptr) {
386 // We simulate the requested event as occurred when ConsumeBool()
387 // returns false. This avoids simulating endless waiting if the
388 // FuzzedDataProvider runs out of data.
389 *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
390 }
391 return true;
392}
393
394bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
395{
396 for (auto& [sock, events] : events_per_sock) {
397 (void)sock;
398 // We simulate the requested event as occurred when ConsumeBool()
399 // returns false. This avoids simulating endless waiting if the
400 // FuzzedDataProvider runs out of data.
401 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
402 }
403 return true;
404}
405
406bool FuzzedSock::IsConnected(std::string& errmsg) const
407{
409 return true;
410 }
411 errmsg = "disconnected at random by the fuzzer";
412 return false;
413}
414
415void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
416{
417 auto successfully_connected = fuzzed_data_provider.ConsumeBool();
418 auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
419 auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
420 auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
421 auto relay_txs = fuzzed_data_provider.ConsumeBool();
422 connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
423}
int flags
Definition: bitcoin-tx.cpp:536
A CService with information about it as peer.
Definition: protocol.h:367
static constexpr SerParams V2_NETWORK
Definition: protocol.h:409
Network address.
Definition: netaddress.h:112
@ V2
BIP155 encoding.
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:172
BIP155Network
BIP155 network ids recognized by this software.
Definition: netaddress.h:263
Information about a peer.
Definition: net.h:673
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
Fast randomness source.
Definition: random.h:377
T ConsumeIntegralInRange(T min, T max)
size_t ConsumeData(void *destination, size_t num_bytes)
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:296
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:310
bool Wait(std::chrono::milliseconds timeout, Event requested, Event *occurred=nullptr) const override
Wait for readiness for input (recv) or output (send).
Definition: net.cpp:374
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:277
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:158
bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock &events_per_sock) const override
Same as Wait(), but wait on many sockets within the same timeout.
Definition: net.cpp:394
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:406
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:235
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:135
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:151
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:129
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:144
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:369
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:356
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:329
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:167
~FuzzedSock() override
Definition: net.cpp:120
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:342
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:113
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:257
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:27
SOCKET m_socket
Contained socket.
Definition: sock.h:275
uint8_t Event
Definition: sock.h:138
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
Definition: sock.h:208
#define INVALID_SOCKET
Definition: compat.h:56
unsigned int SOCKET
Definition: compat.h:46
@ I2P
Definition: logging.h:65
Definition: messages.h:20
static constexpr uint8_t CJDNS_PREFIX
All CJDNS addresses start with 0xFC.
Definition: netaddress.h:82
static constexpr size_t ADDR_CJDNS_SIZE
Size of CJDNS address (in bytes).
Definition: netaddress.h:98
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:92
static constexpr size_t ADDR_I2P_SIZE
Size of I2P address (in bytes).
Definition: netaddress.h:95
static constexpr size_t ADDR_IPV4_SIZE
Size of IPv4 address (in bytes).
Definition: netaddress.h:85
Network
A network type.
Definition: netaddress.h:32
@ NET_I2P
I2P.
Definition: netaddress.h:46
@ NET_CJDNS
CJDNS.
Definition: netaddress.h:49
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:43
@ NET_IPV6
IPv6.
Definition: netaddress.h:40
@ NET_IPV4
IPv4.
Definition: netaddress.h:37
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:53
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:88
@ IPV4
Definition: netbase.cpp:284
@ IPV6
Definition: netbase.cpp:286
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
const char * name
Definition: rest.cpp:49
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:87
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:93
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand) noexcept
Create a CNetAddr.
Definition: net.cpp:28
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:415
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:213
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:133
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:47
std::vector< B > ConsumeFixedLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const size_t length) noexcept
Returns a byte vector of specified size regardless of the number of remaining bytes available from th...
Definition: util.h:256
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:57
void SetFuzzedErrNo(FuzzedDataProvider &fuzzed_data_provider, const std::array< T, size > &errnos)
Sets errno to a value selected from the given std::array errnos.
Definition: util.h:236
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:94
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
assert(!tx.IsCoinBase())