Bitcoin Core  31.0.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 
5 #include <test/fuzz/util/net.h>
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 
27 class 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 
64  DataStream s;
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 
93 template <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 
116  m_fuzzed_data_provider{fuzzed_data_provider},
117  m_selectable{fuzzed_data_provider.ConsumeBool()},
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 
132 void 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 
144 ssize_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 
176 ssize_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 
244 int 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 
266 int 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 
286 int 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  };
299  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
300  return -1;
301  }
302  return 0;
303 }
304 
305 std::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  };
313  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
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 
346 int 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 
365 int 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 
378 int 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 
414 bool 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 
435 bool 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 
448 bool 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();
460  auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
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 }
static void SetMockTime(mock_time_point::duration mock_time_in)
Set mock time for testing.
Definition: time.cpp:70
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:252
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:457
assert(!tx.IsCoinBase())
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:138
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:54
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:128
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:93
IPv4.
Definition: netaddress.h:38
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:171
static constexpr SerParams V2_NETWORK
Definition: protocol.h:409
static constexpr size_t ADDR_IPV4_SIZE
Size of IPv4 address (in bytes).
Definition: netaddress.h:86
SOCKET m_socket
Contained socket.
Definition: sock.h:276
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:365
std::chrono::milliseconds m_time
Used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:183
memcpy(result.begin(), stream.data(), stream.size())
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:448
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:176
#define INVALID_SOCKET
Definition: compat.h:67
std::string ConsumeBytesAsString(size_t num_bytes)
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:57
I2P.
Definition: netaddress.h:47
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:144
static constexpr size_t ADDR_CJDNS_SIZE
Size of CJDNS address (in bytes).
Definition: netaddress.h:99
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:88
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:120
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:89
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
static constexpr size_t ADDR_I2P_SIZE
Size of I2P address (in bytes).
Definition: netaddress.h:96
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:209
const char * name
Definition: rest.cpp:48
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:132
BIP155Network
BIP155 network ids recognized by this software.
Definition: netaddress.h:263
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:250
Fast randomness source.
Definition: random.h:385
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:94
A CService with information about it as peer.
Definition: protocol.h:366
Network
A network type.
Definition: netaddress.h:33
~FuzzedSock() override
Definition: net.cpp:123
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:346
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:305
uint8_t Event
Definition: sock.h:139
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand) noexcept
Create a CNetAddr.
Definition: net.cpp:29
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:244
unsigned int SOCKET
Definition: compat.h:57
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:114
Definition: messages.h:21
static constexpr uint8_t CJDNS_PREFIX
All CJDNS addresses start with 0xFC.
Definition: netaddress.h:83
std::vector< T > ConsumeBytes(size_t num_bytes)
int flags
Definition: bitcoin-tx.cpp:529
Network address.
Definition: netaddress.h:112
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:164
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 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
BIP155 encoding.
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:38
IPv6.
Definition: netaddress.h:41
TOR (v2 or v3)
Definition: netaddress.h:44
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
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:232
static constexpr mock_time_point::duration INITIAL_MOCK_TIME
Definition: time.h:42
RAII helper class that manages a socket and closes it automatically when it goes out of scope...
Definition: sock.h:27
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:396
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:47
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:178
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:378
Information about a peer.
Definition: net.h:679
T ConsumeIntegralInRange(T min, T max)
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:173
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:409
CJDNS.
Definition: netaddress.h:50
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:266
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:286