Bitcoin Core 30.99.0
P2P Digital Currency
net.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-present 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 <ranges>
24#include <thread>
25#include <vector>
26
27class CNode;
28
30{
31 struct NetAux {
32 Network net;
34 size_t len;
35 };
36
37 static constexpr std::array<NetAux, 6> nets{
38 NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE},
39 NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE},
40 NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE},
41 NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE},
42 NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE},
43 NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0},
44 };
45
46 const size_t nets_index{rand == nullptr
47 ? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1)
48 : static_cast<size_t>(rand->randrange(nets.size()))};
49
50 const auto& aux = nets[nets_index];
51
52 CNetAddr addr;
53
54 if (aux.net == Network::NET_INTERNAL) {
55 if (rand == nullptr) {
57 } else {
58 const auto v = rand->randbytes(32);
59 addr.SetInternal(std::string{v.begin(), v.end()});
60 }
61 return addr;
62 }
63
65
66 s << static_cast<uint8_t>(aux.bip155);
67
68 std::vector<uint8_t> addr_bytes;
69 if (rand == nullptr) {
70 addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len);
71 addr_bytes.resize(aux.len);
72 } else {
73 addr_bytes = rand->randbytes(aux.len);
74 }
75 if (aux.net == NET_IPV6 && addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS.
76 addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do.
77 }
78 if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid().
79 addr_bytes[0] = CJDNS_PREFIX;
80 }
81 s << addr_bytes;
82
83 s >> CAddress::V2_NETWORK(addr);
84
85 return addr;
86}
87
89{
91}
92
93template <typename P>
95{
96 constexpr std::array ADDR_ENCODINGS{
99 };
100 constexpr std::array ADDR_FORMATS{
103 };
104 if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {
105 return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};
106 }
107 if constexpr (std::is_same_v<P, CAddress::SerParams>) {
108 return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};
109 }
110}
113
115 : Sock{fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET)},
116 m_fuzzed_data_provider{fuzzed_data_provider},
117 m_selectable{fuzzed_data_provider.ConsumeBool()},
118 m_time{MockableSteadyClock::INITIAL_MOCK_TIME}
119{
120 ElapseTime(std::chrono::seconds(0)); // start mocking the steady clock.
121}
122
124{
125 // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
126 // close(m_socket) if m_socket is not INVALID_SOCKET.
127 // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
128 // theoretically may concide with a real opened file descriptor).
130}
131
132void FuzzedSock::ElapseTime(std::chrono::milliseconds duration) const
133{
134 m_time += duration;
136}
137
139{
140 assert(false && "Move of Sock into FuzzedSock not allowed.");
141 return *this;
142}
143
144ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
145{
146 constexpr std::array send_errnos{
147 EACCES,
148 EAGAIN,
149 EALREADY,
150 EBADF,
151 ECONNRESET,
152 EDESTADDRREQ,
153 EFAULT,
154 EINTR,
155 EINVAL,
156 EISCONN,
157 EMSGSIZE,
158 ENOBUFS,
159 ENOMEM,
160 ENOTCONN,
161 ENOTSOCK,
162 EOPNOTSUPP,
163 EPIPE,
164 EWOULDBLOCK,
165 };
167 return len;
168 }
169 const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
170 if (r == -1) {
172 }
173 return r;
174}
175
176ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
177{
178 // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
179 // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
180 // returning -1 and setting errno to EAGAIN repeatedly.
181 constexpr std::array recv_errnos{
182 ECONNREFUSED,
183 EAGAIN,
184 EBADF,
185 EFAULT,
186 EINTR,
187 EINVAL,
188 ENOMEM,
189 ENOTCONN,
190 ENOTSOCK,
191 EWOULDBLOCK,
192 };
193 assert(buf != nullptr || len == 0);
194
195 // Do the latency before any of the "return" statements.
196 if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
197 std::this_thread::sleep_for(std::chrono::milliseconds{2});
198 }
199
200 if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
201 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
202 if (r == -1) {
204 }
205 return r;
206 }
207
208 size_t copied_so_far{0};
209
210 if (!m_peek_data.empty()) {
211 // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
212 const size_t copy_len{std::min(len, m_peek_data.size())};
213 std::memcpy(buf, m_peek_data.data(), copy_len);
214 copied_so_far += copy_len;
215 if ((flags & MSG_PEEK) == 0) {
216 m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
217 }
218 }
219
220 if (copied_so_far == len) {
221 return copied_so_far;
222 }
223
224 auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
225 if (new_data.empty()) return copied_so_far;
226
227 std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
228 copied_so_far += new_data.size();
229
230 if ((flags & MSG_PEEK) != 0) {
231 m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
232 }
233
234 if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
235 return copied_so_far;
236 }
237
238 // Pad to len bytes.
239 std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
240
241 return len;
242}
243
244int FuzzedSock::Connect(const sockaddr*, socklen_t) const
245{
246 // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
247 // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
248 // returning -1 and setting errno to EAGAIN repeatedly.
249 constexpr std::array connect_errnos{
250 ECONNREFUSED,
251 EAGAIN,
252 ECONNRESET,
253 EHOSTUNREACH,
254 EINPROGRESS,
255 EINTR,
256 ENETUNREACH,
257 ETIMEDOUT,
258 };
260 SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
261 return -1;
262 }
263 return 0;
264}
265
266int FuzzedSock::Bind(const sockaddr*, socklen_t) const
267{
268 // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
269 // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
270 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
271 // repeatedly because proper code should retry on temporary errors, leading to an
272 // infinite loop.
273 constexpr std::array bind_errnos{
274 EACCES,
275 EADDRINUSE,
276 EADDRNOTAVAIL,
277 EAGAIN,
278 };
281 return -1;
282 }
283 return 0;
284}
285
286int FuzzedSock::Listen(int) const
287{
288 // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
289 // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
290 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
291 // repeatedly because proper code should retry on temporary errors, leading to an
292 // infinite loop.
293 constexpr std::array listen_errnos{
294 EADDRINUSE,
295 EINVAL,
296 EOPNOTSUPP,
297 };
300 return -1;
301 }
302 return 0;
303}
304
305std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
306{
307 constexpr std::array accept_errnos{
308 ECONNABORTED,
309 EINTR,
310 ENOMEM,
311 };
314 return std::unique_ptr<FuzzedSock>();
315 }
316 if (addr != nullptr) {
317 // Set a fuzzed address in the output argument addr.
318 memset(addr, 0x00, *addr_len);
320 // IPv4
321 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));
322 if (*addr_len >= write_len) {
323 *addr_len = write_len;
324 auto addr4 = reinterpret_cast<sockaddr_in*>(addr);
325 addr4->sin_family = AF_INET;
326 const auto sin_addr_bytes{m_fuzzed_data_provider.ConsumeBytes<std::byte>(sizeof(addr4->sin_addr))};
327 std::ranges::copy(sin_addr_bytes, reinterpret_cast<std::byte*>(&addr4->sin_addr));
328 addr4->sin_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
329 }
330 } else {
331 // IPv6
332 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in6));
333 if (*addr_len >= write_len) {
334 *addr_len = write_len;
335 auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
336 addr6->sin6_family = AF_INET6;
337 const auto sin_addr_bytes{m_fuzzed_data_provider.ConsumeBytes<std::byte>(sizeof(addr6->sin6_addr))};
338 std::ranges::copy(sin_addr_bytes, reinterpret_cast<std::byte*>(&addr6->sin6_addr));
339 addr6->sin6_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
340 }
341 }
342 }
343 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
344}
345
346int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
347{
348 constexpr std::array getsockopt_errnos{
349 ENOMEM,
350 ENOBUFS,
351 };
353 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
354 return -1;
355 }
356 if (opt_val == nullptr) {
357 return 0;
358 }
359 std::memcpy(opt_val,
361 *opt_len);
362 return 0;
363}
364
365int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
366{
367 constexpr std::array setsockopt_errnos{
368 ENOMEM,
369 ENOBUFS,
370 };
372 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
373 return -1;
374 }
375 return 0;
376}
377
378int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
379{
380 constexpr std::array getsockname_errnos{
381 ECONNRESET,
382 ENOBUFS,
383 };
385 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
386 return -1;
387 }
388 assert(name_len);
389 const auto bytes{ConsumeRandomLengthByteVector(m_fuzzed_data_provider, *name_len)};
390 if (bytes.size() < (int)sizeof(sockaddr)) return -1;
391 std::memcpy(name, bytes.data(), bytes.size());
392 *name_len = bytes.size();
393 return 0;
394}
395
397{
398 constexpr std::array setnonblocking_errnos{
399 EBADF,
400 EPERM,
401 };
403 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
404 return false;
405 }
406 return true;
407}
408
410{
411 return m_selectable;
412}
413
414bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
415{
416 constexpr std::array wait_errnos{
417 EBADF,
418 EINTR,
419 EINVAL,
420 };
423 return false;
424 }
425 if (occurred != nullptr) {
426 // We simulate the requested event as occurred when ConsumeBool()
427 // returns false. This avoids simulating endless waiting if the
428 // FuzzedDataProvider runs out of data.
429 *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
430 }
431 ElapseTime(timeout);
432 return true;
433}
434
435bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
436{
437 for (auto& [sock, events] : events_per_sock) {
438 (void)sock;
439 // We simulate the requested event as occurred when ConsumeBool()
440 // returns false. This avoids simulating endless waiting if the
441 // FuzzedDataProvider runs out of data.
442 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
443 }
444 ElapseTime(timeout);
445 return true;
446}
447
448bool FuzzedSock::IsConnected(std::string& errmsg) const
449{
451 return true;
452 }
453 errmsg = "disconnected at random by the fuzzer";
454 return false;
455}
456
458{
459 auto successfully_connected = fuzzed_data_provider.ConsumeBool();
462 auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
463 auto relay_txs = fuzzed_data_provider.ConsumeBool();
464 connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
465}
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:113
@ V2
BIP155 encoding.
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:173
BIP155Network
BIP155 network ids recognized by this software.
Definition: netaddress.h:264
Information about a peer.
Definition: net.h:676
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:130
Fast randomness source.
Definition: random.h:386
std::string ConsumeBytesAsString(size_t num_bytes)
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:305
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:346
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:414
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:286
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:435
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:132
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:448
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:244
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:144
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:138
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:409
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:396
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:365
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:176
~FuzzedSock() override
Definition: net.cpp:123
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:378
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:114
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:266
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:21
static constexpr uint8_t CJDNS_PREFIX
All CJDNS addresses start with 0xFC.
Definition: netaddress.h:83
static constexpr size_t ADDR_CJDNS_SIZE
Size of CJDNS address (in bytes).
Definition: netaddress.h:99
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:93
static constexpr size_t ADDR_I2P_SIZE
Size of I2P address (in bytes).
Definition: netaddress.h:96
static constexpr size_t ADDR_IPV4_SIZE
Size of IPv4 address (in bytes).
Definition: netaddress.h:86
Network
A network type.
Definition: netaddress.h:33
@ NET_I2P
I2P.
Definition: netaddress.h:47
@ NET_CJDNS
CJDNS.
Definition: netaddress.h:50
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:44
@ NET_IPV6
IPv6.
Definition: netaddress.h:41
@ NET_IPV4
IPv4.
Definition: netaddress.h:38
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:54
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:89
@ 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:48
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:88
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:94
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand) noexcept
Create a CNetAddr.
Definition: net.cpp:29
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:457
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())
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:38