Bitcoin Core 30.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 if (addr != nullptr) {
316 // Set a fuzzed address in the output argument addr.
317 memset(addr, 0x00, *addr_len);
319 // IPv4
320 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));
321 if (*addr_len >= write_len) {
322 *addr_len = write_len;
323 auto addr4 = reinterpret_cast<sockaddr_in*>(addr);
324 addr4->sin_family = AF_INET;
325 const auto sin_addr_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(sizeof(addr4->sin_addr));
326 memcpy(&addr4->sin_addr, sin_addr_bytes.data(), sin_addr_bytes.size());
327 addr4->sin_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
328 }
329 } else {
330 // IPv6
331 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in6));
332 if (*addr_len >= write_len) {
333 *addr_len = write_len;
334 auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
335 addr6->sin6_family = AF_INET6;
336 const auto sin_addr_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(sizeof(addr6->sin6_addr));
337 memcpy(&addr6->sin6_addr, sin_addr_bytes.data(), sin_addr_bytes.size());
338 addr6->sin6_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
339 }
340 }
341 }
342 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
343}
344
345int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
346{
347 constexpr std::array getsockopt_errnos{
348 ENOMEM,
349 ENOBUFS,
350 };
352 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
353 return -1;
354 }
355 if (opt_val == nullptr) {
356 return 0;
357 }
358 std::memcpy(opt_val,
360 *opt_len);
361 return 0;
362}
363
364int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
365{
366 constexpr std::array setsockopt_errnos{
367 ENOMEM,
368 ENOBUFS,
369 };
371 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
372 return -1;
373 }
374 return 0;
375}
376
377int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
378{
379 constexpr std::array getsockname_errnos{
380 ECONNRESET,
381 ENOBUFS,
382 };
384 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
385 return -1;
386 }
387 assert(name_len);
388 const auto bytes{ConsumeRandomLengthByteVector(m_fuzzed_data_provider, *name_len)};
389 if (bytes.size() < (int)sizeof(sockaddr)) return -1;
390 std::memcpy(name, bytes.data(), bytes.size());
391 *name_len = bytes.size();
392 return 0;
393}
394
396{
397 constexpr std::array setnonblocking_errnos{
398 EBADF,
399 EPERM,
400 };
402 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
403 return false;
404 }
405 return true;
406}
407
409{
410 return m_selectable;
411}
412
413bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
414{
415 constexpr std::array wait_errnos{
416 EBADF,
417 EINTR,
418 EINVAL,
419 };
422 return false;
423 }
424 if (occurred != nullptr) {
425 // We simulate the requested event as occurred when ConsumeBool()
426 // returns false. This avoids simulating endless waiting if the
427 // FuzzedDataProvider runs out of data.
428 *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
429 }
430 ElapseTime(timeout);
431 return true;
432}
433
434bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
435{
436 for (auto& [sock, events] : events_per_sock) {
437 (void)sock;
438 // We simulate the requested event as occurred when ConsumeBool()
439 // returns false. This avoids simulating endless waiting if the
440 // FuzzedDataProvider runs out of data.
441 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
442 }
443 ElapseTime(timeout);
444 return true;
445}
446
447bool FuzzedSock::IsConnected(std::string& errmsg) const
448{
450 return true;
451 }
452 errmsg = "disconnected at random by the fuzzer";
453 return false;
454}
455
456void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
457{
458 auto successfully_connected = fuzzed_data_provider.ConsumeBool();
459 auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
460 auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
461 auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
462 auto relay_txs = fuzzed_data_provider.ConsumeBool();
463 connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
464}
int flags
Definition: bitcoin-tx.cpp:529
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:675
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:130
Fast randomness source.
Definition: random.h:386
std::vector< T > ConsumeBytes(size_t num_bytes)
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:345
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:413
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:177
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:434
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:447
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:170
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:163
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:408
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:395
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:364
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:377
std::chrono::milliseconds m_time
Used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:182
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:55
unsigned int SOCKET
Definition: compat.h:45
@ I2P
Definition: logging.h:88
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:292
@ IPV6
Definition: netbase.cpp:294
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
const char * name
Definition: rest.cpp:50
Version of SteadyClock that is mockable in the context of tests (set the current value with SetMockTi...
Definition: time.h:38
static void SetMockTime(mock_time_point::duration mock_time_in)
Set mock time for testing.
Definition: time.cpp:66
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:456
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:247
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:116
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
assert(!tx.IsCoinBase())