Bitcoin Core 31.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_clock{clock}
119{
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
132{
133 assert(false && "Move of Sock into FuzzedSock not allowed.");
134 return *this;
135}
136
137ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
138{
139 constexpr std::array send_errnos{
140 EACCES,
141 EAGAIN,
142 EALREADY,
143 EBADF,
144 ECONNRESET,
145 EDESTADDRREQ,
146 EFAULT,
147 EINTR,
148 EINVAL,
149 EISCONN,
150 EMSGSIZE,
151 ENOBUFS,
152 ENOMEM,
153 ENOTCONN,
154 ENOTSOCK,
155 EOPNOTSUPP,
156 EPIPE,
157 EWOULDBLOCK,
158 };
160 return len;
161 }
162 const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
163 if (r == -1) {
165 }
166 return r;
167}
168
169ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
170{
171 // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
172 // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
173 // returning -1 and setting errno to EAGAIN repeatedly.
174 constexpr std::array recv_errnos{
175 ECONNREFUSED,
176 EAGAIN,
177 EBADF,
178 EFAULT,
179 EINTR,
180 EINVAL,
181 ENOMEM,
182 ENOTCONN,
183 ENOTSOCK,
184 EWOULDBLOCK,
185 };
186 assert(buf != nullptr || len == 0);
187
188 // Do the latency before any of the "return" statements.
189 if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
190 std::this_thread::sleep_for(std::chrono::milliseconds{2});
191 }
192
193 if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
194 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
195 if (r == -1) {
197 }
198 return r;
199 }
200
201 size_t copied_so_far{0};
202
203 if (!m_peek_data.empty()) {
204 // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
205 const size_t copy_len{std::min(len, m_peek_data.size())};
206 std::memcpy(buf, m_peek_data.data(), copy_len);
207 copied_so_far += copy_len;
208 if ((flags & MSG_PEEK) == 0) {
209 m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
210 }
211 }
212
213 if (copied_so_far == len) {
214 return copied_so_far;
215 }
216
217 auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
218 if (new_data.empty()) return copied_so_far;
219
220 std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
221 copied_so_far += new_data.size();
222
223 if ((flags & MSG_PEEK) != 0) {
224 m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
225 }
226
227 if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
228 return copied_so_far;
229 }
230
231 // Pad to len bytes.
232 std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
233
234 return len;
235}
236
237int FuzzedSock::Connect(const sockaddr*, socklen_t) const
238{
239 // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
240 // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
241 // returning -1 and setting errno to EAGAIN repeatedly.
242 constexpr std::array connect_errnos{
243 ECONNREFUSED,
244 EAGAIN,
245 ECONNRESET,
246 EHOSTUNREACH,
247 EINPROGRESS,
248 EINTR,
249 ENETUNREACH,
250 ETIMEDOUT,
251 };
253 SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
254 return -1;
255 }
256 return 0;
257}
258
259int FuzzedSock::Bind(const sockaddr*, socklen_t) const
260{
261 // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
262 // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
263 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
264 // repeatedly because proper code should retry on temporary errors, leading to an
265 // infinite loop.
266 constexpr std::array bind_errnos{
267 EACCES,
268 EADDRINUSE,
269 EADDRNOTAVAIL,
270 EAGAIN,
271 };
274 return -1;
275 }
276 return 0;
277}
278
279int FuzzedSock::Listen(int) const
280{
281 // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
282 // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
283 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
284 // repeatedly because proper code should retry on temporary errors, leading to an
285 // infinite loop.
286 constexpr std::array listen_errnos{
287 EADDRINUSE,
288 EINVAL,
289 EOPNOTSUPP,
290 };
293 return -1;
294 }
295 return 0;
296}
297
298std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
299{
300 constexpr std::array accept_errnos{
301 ECONNABORTED,
302 EINTR,
303 ENOMEM,
304 };
307 return std::unique_ptr<FuzzedSock>();
308 }
309 if (addr != nullptr) {
310 // Set a fuzzed address in the output argument addr.
311 memset(addr, 0x00, *addr_len);
313 // IPv4
314 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));
315 if (*addr_len >= write_len) {
316 *addr_len = write_len;
317 auto addr4 = reinterpret_cast<sockaddr_in*>(addr);
318 addr4->sin_family = AF_INET;
319 const auto sin_addr_bytes{m_fuzzed_data_provider.ConsumeBytes<std::byte>(sizeof(addr4->sin_addr))};
320 std::ranges::copy(sin_addr_bytes, reinterpret_cast<std::byte*>(&addr4->sin_addr));
321 addr4->sin_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
322 }
323 } else {
324 // IPv6
325 const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in6));
326 if (*addr_len >= write_len) {
327 *addr_len = write_len;
328 auto addr6 = reinterpret_cast<sockaddr_in6*>(addr);
329 addr6->sin6_family = AF_INET6;
330 const auto sin_addr_bytes{m_fuzzed_data_provider.ConsumeBytes<std::byte>(sizeof(addr6->sin6_addr))};
331 std::ranges::copy(sin_addr_bytes, reinterpret_cast<std::byte*>(&addr6->sin6_addr));
332 addr6->sin6_port = m_fuzzed_data_provider.ConsumeIntegralInRange<uint16_t>(1, 65535);
333 }
334 }
335 }
336 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider, m_clock);
337}
338
339int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
340{
341 constexpr std::array getsockopt_errnos{
342 ENOMEM,
343 ENOBUFS,
344 };
346 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
347 return -1;
348 }
349 if (opt_val == nullptr) {
350 return 0;
351 }
352 std::memcpy(opt_val,
354 *opt_len);
355 return 0;
356}
357
358int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
359{
360 constexpr std::array setsockopt_errnos{
361 ENOMEM,
362 ENOBUFS,
363 };
365 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
366 return -1;
367 }
368 return 0;
369}
370
371int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
372{
373 constexpr std::array getsockname_errnos{
374 ECONNRESET,
375 ENOBUFS,
376 };
378 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
379 return -1;
380 }
381 assert(name_len);
382 const auto bytes{ConsumeRandomLengthByteVector(m_fuzzed_data_provider, *name_len)};
383 if (bytes.size() < (int)sizeof(sockaddr)) return -1;
384 std::memcpy(name, bytes.data(), bytes.size());
385 *name_len = bytes.size();
386 return 0;
387}
388
390{
391 constexpr std::array setnonblocking_errnos{
392 EBADF,
393 EPERM,
394 };
396 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
397 return false;
398 }
399 return true;
400}
401
403{
404 return m_selectable;
405}
406
407bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
408{
409 constexpr std::array wait_errnos{
410 EBADF,
411 EINTR,
412 EINVAL,
413 };
416 return false;
417 }
418 if (occurred != nullptr) {
419 // We simulate the requested event as occurred when ConsumeBool()
420 // returns false. This avoids simulating endless waiting if the
421 // FuzzedDataProvider runs out of data.
422 *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
423 }
424 m_clock += timeout;
425 return true;
426}
427
428bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
429{
430 for (auto& [sock, events] : events_per_sock) {
431 (void)sock;
432 // We simulate the requested event as occurred when ConsumeBool()
433 // returns false. This avoids simulating endless waiting if the
434 // FuzzedDataProvider runs out of data.
435 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
436 }
437 m_clock += timeout;
438 return true;
439}
440
441bool FuzzedSock::IsConnected(std::string& errmsg) const
442{
444 return true;
445 }
446 errmsg = "disconnected at random by the fuzzer";
447 return false;
448}
449
451{
452 auto successfully_connected = fuzzed_data_provider.ConsumeBool();
455 auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
456 auto relay_txs = fuzzed_data_provider.ConsumeBool();
457 connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
458}
int flags
Definition: bitcoin-tx.cpp:530
A CService with information about it as peer.
Definition: protocol.h:379
static constexpr SerParams V2_NETWORK
Definition: protocol.h:421
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:263
Information about a peer.
Definition: net.h:681
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:165
Helper to initialize the global MockableSteadyClock, let a duration elapse, and reset it after use in...
Definition: time.h:29
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:298
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:339
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:407
FakeSteadyClock & m_clock
Externally-provided context used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:188
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:279
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:179
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:428
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:441
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:237
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:137
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:172
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:131
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:165
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:402
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:389
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:358
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:169
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider, FakeSteadyClock &clock)
Definition: net.cpp:114
~FuzzedSock() override
Definition: net.cpp:122
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:371
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:259
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:35
SOCKET m_socket
Contained socket.
Definition: sock.h:283
uint8_t Event
Definition: sock.h:146
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:216
#define INVALID_SOCKET
Definition: compat.h:67
unsigned int SOCKET
Definition: compat.h:57
@ I2P
Definition: categories.h:37
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:288
@ IPV6
Definition: netbase.cpp:290
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
const char * name
Definition: rest.cpp:50
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:450
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:250
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:147
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:57
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:280
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:63
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:260
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:121
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:35
assert(!tx.IsCoinBase())
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:39