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 m_time{MockableSteadyClock::INITIAL_MOCK_TIME}
118{
119 ElapseTime(std::chrono::seconds(0)); // start mocking the steady clock.
120}
121
123{
124 // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
125 // close(m_socket) if m_socket is not INVALID_SOCKET.
126 // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
127 // theoretically may concide with a real opened file descriptor).
129}
130
131void FuzzedSock::ElapseTime(std::chrono::milliseconds duration) const
132{
133 m_time += duration;
135}
136
138{
139 assert(false && "Move of Sock into FuzzedSock not allowed.");
140 return *this;
141}
142
143ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
144{
145 constexpr std::array send_errnos{
146 EACCES,
147 EAGAIN,
148 EALREADY,
149 EBADF,
150 ECONNRESET,
151 EDESTADDRREQ,
152 EFAULT,
153 EINTR,
154 EINVAL,
155 EISCONN,
156 EMSGSIZE,
157 ENOBUFS,
158 ENOMEM,
159 ENOTCONN,
160 ENOTSOCK,
161 EOPNOTSUPP,
162 EPIPE,
163 EWOULDBLOCK,
164 };
166 return len;
167 }
168 const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
169 if (r == -1) {
171 }
172 return r;
173}
174
175ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
176{
177 // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
178 // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
179 // returning -1 and setting errno to EAGAIN repeatedly.
180 constexpr std::array recv_errnos{
181 ECONNREFUSED,
182 EAGAIN,
183 EBADF,
184 EFAULT,
185 EINTR,
186 EINVAL,
187 ENOMEM,
188 ENOTCONN,
189 ENOTSOCK,
190 EWOULDBLOCK,
191 };
192 assert(buf != nullptr || len == 0);
193
194 // Do the latency before any of the "return" statements.
195 if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
196 std::this_thread::sleep_for(std::chrono::milliseconds{2});
197 }
198
199 if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
200 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
201 if (r == -1) {
203 }
204 return r;
205 }
206
207 size_t copied_so_far{0};
208
209 if (!m_peek_data.empty()) {
210 // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
211 const size_t copy_len{std::min(len, m_peek_data.size())};
212 std::memcpy(buf, m_peek_data.data(), copy_len);
213 copied_so_far += copy_len;
214 if ((flags & MSG_PEEK) == 0) {
215 m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
216 }
217 }
218
219 if (copied_so_far == len) {
220 return copied_so_far;
221 }
222
223 auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
224 if (new_data.empty()) return copied_so_far;
225
226 std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
227 copied_so_far += new_data.size();
228
229 if ((flags & MSG_PEEK) != 0) {
230 m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
231 }
232
233 if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
234 return copied_so_far;
235 }
236
237 // Pad to len bytes.
238 std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
239
240 return len;
241}
242
243int FuzzedSock::Connect(const sockaddr*, socklen_t) const
244{
245 // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
246 // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
247 // returning -1 and setting errno to EAGAIN repeatedly.
248 constexpr std::array connect_errnos{
249 ECONNREFUSED,
250 EAGAIN,
251 ECONNRESET,
252 EHOSTUNREACH,
253 EINPROGRESS,
254 EINTR,
255 ENETUNREACH,
256 ETIMEDOUT,
257 };
259 SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
260 return -1;
261 }
262 return 0;
263}
264
265int FuzzedSock::Bind(const sockaddr*, socklen_t) const
266{
267 // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
268 // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
269 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
270 // repeatedly because proper code should retry on temporary errors, leading to an
271 // infinite loop.
272 constexpr std::array bind_errnos{
273 EACCES,
274 EADDRINUSE,
275 EADDRNOTAVAIL,
276 EAGAIN,
277 };
280 return -1;
281 }
282 return 0;
283}
284
285int FuzzedSock::Listen(int) const
286{
287 // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
288 // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
289 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
290 // repeatedly because proper code should retry on temporary errors, leading to an
291 // infinite loop.
292 constexpr std::array listen_errnos{
293 EADDRINUSE,
294 EINVAL,
295 EOPNOTSUPP,
296 };
299 return -1;
300 }
301 return 0;
302}
303
304std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
305{
306 constexpr std::array accept_errnos{
307 ECONNABORTED,
308 EINTR,
309 ENOMEM,
310 };
313 return std::unique_ptr<FuzzedSock>();
314 }
315 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
316}
317
318int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
319{
320 constexpr std::array getsockopt_errnos{
321 ENOMEM,
322 ENOBUFS,
323 };
325 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
326 return -1;
327 }
328 if (opt_val == nullptr) {
329 return 0;
330 }
331 std::memcpy(opt_val,
333 *opt_len);
334 return 0;
335}
336
337int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
338{
339 constexpr std::array setsockopt_errnos{
340 ENOMEM,
341 ENOBUFS,
342 };
344 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
345 return -1;
346 }
347 return 0;
348}
349
350int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
351{
352 constexpr std::array getsockname_errnos{
353 ECONNRESET,
354 ENOBUFS,
355 };
357 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
358 return -1;
359 }
360 assert(name_len);
361 const auto bytes{ConsumeRandomLengthByteVector(m_fuzzed_data_provider, *name_len)};
362 if (bytes.size() < (int)sizeof(sockaddr)) return -1;
363 std::memcpy(name, bytes.data(), bytes.size());
364 *name_len = bytes.size();
365 return 0;
366}
367
369{
370 constexpr std::array setnonblocking_errnos{
371 EBADF,
372 EPERM,
373 };
375 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
376 return false;
377 }
378 return true;
379}
380
382{
383 return m_selectable;
384}
385
386bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
387{
388 constexpr std::array wait_errnos{
389 EBADF,
390 EINTR,
391 EINVAL,
392 };
395 return false;
396 }
397 if (occurred != nullptr) {
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 *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
402 }
403 ElapseTime(timeout);
404 return true;
405}
406
407bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
408{
409 for (auto& [sock, events] : events_per_sock) {
410 (void)sock;
411 // We simulate the requested event as occurred when ConsumeBool()
412 // returns false. This avoids simulating endless waiting if the
413 // FuzzedDataProvider runs out of data.
414 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
415 }
416 ElapseTime(timeout);
417 return true;
418}
419
420bool FuzzedSock::IsConnected(std::string& errmsg) const
421{
423 return true;
424 }
425 errmsg = "disconnected at random by the fuzzer";
426 return false;
427}
428
429void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
430{
431 auto successfully_connected = fuzzed_data_provider.ConsumeBool();
432 auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
433 auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
434 auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
435 auto relay_txs = fuzzed_data_provider.ConsumeBool();
436 connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
437}
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)
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:304
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:318
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:386
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:285
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:407
void ElapseTime(std::chrono::milliseconds duration) const
Set the value of the mocked steady clock such as that many ms have passed.
Definition: net.cpp:131
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:420
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:243
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:143
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:137
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:381
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:368
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:337
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:175
~FuzzedSock() override
Definition: net.cpp:122
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:350
std::chrono::milliseconds m_time
Used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:163
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:113
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:265
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
Version of SteadyClock that is mockable in the context of tests (set the current value with SetMockTi...
Definition: time.h:38
static void SetMockTime(std::chrono::milliseconds mock_time_in)
Set mock time for testing.
Definition: time.cpp:65
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:429
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:223
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:95
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
assert(!tx.IsCoinBase())