Bitcoin Core  25.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 
5 #include <test/fuzz/util/net.h>
6 
7 #include <compat/compat.h>
8 #include <netaddress.h>
9 #include <protocol.h>
11 #include <test/fuzz/util.h>
12 #include <test/util/net.h>
13 #include <util/sock.h>
14 #include <util/time.h>
15 #include <version.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 
26 class CNode;
27 
28 CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
29 {
30  const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
31  CNetAddr net_addr;
32  if (network == Network::NET_IPV4) {
33  in_addr v4_addr = {};
34  v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
35  net_addr = CNetAddr{v4_addr};
36  } else if (network == Network::NET_IPV6) {
37  if (fuzzed_data_provider.remaining_bytes() >= 16) {
38  in6_addr v6_addr = {};
39  memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
40  net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
41  }
42  } else if (network == Network::NET_INTERNAL) {
43  net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
44  } else if (network == Network::NET_ONION) {
45  auto pub_key{fuzzed_data_provider.ConsumeBytes<uint8_t>(ADDR_TORV3_SIZE)};
46  pub_key.resize(ADDR_TORV3_SIZE);
47  const bool ok{net_addr.SetSpecial(OnionToString(pub_key))};
48  assert(ok);
49  }
50  return net_addr;
51 }
52 
53 CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
54 {
55  return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
56 }
57 
58 template <typename P>
59 P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept
60 {
61  constexpr std::array ADDR_ENCODINGS{
64  };
65  constexpr std::array ADDR_FORMATS{
68  };
69  if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {
70  return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};
71  }
72  if constexpr (std::is_same_v<P, CAddress::SerParams>) {
73  return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};
74  }
75 }
78 
80  : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}
81 {
83 }
84 
86 {
87  // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
88  // close(m_socket) if m_socket is not INVALID_SOCKET.
89  // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
90  // theoretically may concide with a real opened file descriptor).
92 }
93 
95 {
96  assert(false && "Move of Sock into FuzzedSock not allowed.");
97  return *this;
98 }
99 
100 ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
101 {
102  constexpr std::array send_errnos{
103  EACCES,
104  EAGAIN,
105  EALREADY,
106  EBADF,
107  ECONNRESET,
108  EDESTADDRREQ,
109  EFAULT,
110  EINTR,
111  EINVAL,
112  EISCONN,
113  EMSGSIZE,
114  ENOBUFS,
115  ENOMEM,
116  ENOTCONN,
117  ENOTSOCK,
118  EOPNOTSUPP,
119  EPIPE,
120  EWOULDBLOCK,
121  };
123  return len;
124  }
125  const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
126  if (r == -1) {
128  }
129  return r;
130 }
131 
132 ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
133 {
134  // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
135  // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
136  // returning -1 and setting errno to EAGAIN repeatedly.
137  constexpr std::array recv_errnos{
138  ECONNREFUSED,
139  EAGAIN,
140  EBADF,
141  EFAULT,
142  EINTR,
143  EINVAL,
144  ENOMEM,
145  ENOTCONN,
146  ENOTSOCK,
147  EWOULDBLOCK,
148  };
149  assert(buf != nullptr || len == 0);
150  if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
151  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
152  if (r == -1) {
154  }
155  return r;
156  }
157  std::vector<uint8_t> random_bytes;
158  bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
159  if (m_peek_data.has_value()) {
160  // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
161  random_bytes.assign({m_peek_data.value()});
162  if ((flags & MSG_PEEK) == 0) {
163  m_peek_data.reset();
164  }
165  pad_to_len_bytes = false;
166  } else if ((flags & MSG_PEEK) != 0) {
167  // New call with `MSG_PEEK`.
168  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
169  if (!random_bytes.empty()) {
170  m_peek_data = random_bytes[0];
171  pad_to_len_bytes = false;
172  }
173  } else {
174  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
176  }
177  if (random_bytes.empty()) {
178  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
179  if (r == -1) {
181  }
182  return r;
183  }
184  std::memcpy(buf, random_bytes.data(), random_bytes.size());
185  if (pad_to_len_bytes) {
186  if (len > random_bytes.size()) {
187  std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
188  }
189  return len;
190  }
191  if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
192  std::this_thread::sleep_for(std::chrono::milliseconds{2});
193  }
194  return random_bytes.size();
195 }
196 
197 int FuzzedSock::Connect(const sockaddr*, socklen_t) const
198 {
199  // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
200  // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
201  // returning -1 and setting errno to EAGAIN repeatedly.
202  constexpr std::array connect_errnos{
203  ECONNREFUSED,
204  EAGAIN,
205  ECONNRESET,
206  EHOSTUNREACH,
207  EINPROGRESS,
208  EINTR,
209  ENETUNREACH,
210  ETIMEDOUT,
211  };
213  SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
214  return -1;
215  }
216  return 0;
217 }
218 
219 int FuzzedSock::Bind(const sockaddr*, socklen_t) const
220 {
221  // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
222  // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
223  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
224  // repeatedly because proper code should retry on temporary errors, leading to an
225  // infinite loop.
226  constexpr std::array bind_errnos{
227  EACCES,
228  EADDRINUSE,
229  EADDRNOTAVAIL,
230  EAGAIN,
231  };
234  return -1;
235  }
236  return 0;
237 }
238 
239 int FuzzedSock::Listen(int) const
240 {
241  // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
242  // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
243  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
244  // repeatedly because proper code should retry on temporary errors, leading to an
245  // infinite loop.
246  constexpr std::array listen_errnos{
247  EADDRINUSE,
248  EINVAL,
249  EOPNOTSUPP,
250  };
252  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
253  return -1;
254  }
255  return 0;
256 }
257 
258 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
259 {
260  constexpr std::array accept_errnos{
261  ECONNABORTED,
262  EINTR,
263  ENOMEM,
264  };
266  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
267  return std::unique_ptr<FuzzedSock>();
268  }
269  return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
270 }
271 
272 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
273 {
274  constexpr std::array getsockopt_errnos{
275  ENOMEM,
276  ENOBUFS,
277  };
279  SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
280  return -1;
281  }
282  if (opt_val == nullptr) {
283  return 0;
284  }
285  std::memcpy(opt_val,
287  *opt_len);
288  return 0;
289 }
290 
291 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
292 {
293  constexpr std::array setsockopt_errnos{
294  ENOMEM,
295  ENOBUFS,
296  };
298  SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
299  return -1;
300  }
301  return 0;
302 }
303 
304 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
305 {
306  constexpr std::array getsockname_errnos{
307  ECONNRESET,
308  ENOBUFS,
309  };
311  SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
312  return -1;
313  }
314  *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
315  return 0;
316 }
317 
319 {
320  constexpr std::array setnonblocking_errnos{
321  EBADF,
322  EPERM,
323  };
325  SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
326  return false;
327  }
328  return true;
329 }
330 
332 {
333  return m_selectable;
334 }
335 
336 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
337 {
338  constexpr std::array wait_errnos{
339  EBADF,
340  EINTR,
341  EINVAL,
342  };
345  return false;
346  }
347  if (occurred != nullptr) {
348  *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
349  }
350  return true;
351 }
352 
353 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
354 {
355  for (auto& [sock, events] : events_per_sock) {
356  (void)sock;
357  events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
358  }
359  return true;
360 }
361 
362 bool FuzzedSock::IsConnected(std::string& errmsg) const
363 {
365  return true;
366  }
367  errmsg = "disconnected at random by the fuzzer";
368  return false;
369 }
370 
371 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
372 {
373  connman.Handshake(node,
374  /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
375  /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
376  /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
377  /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
378  /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
379 }
int flags
Definition: bitcoin-tx.cpp:528
A CService with information about it as peer.
Definition: protocol.h:360
Network address.
Definition: netaddress.h:112
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
Definition: netaddress.cpp:208
@ V2
BIP155 encoding.
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:169
Information about a peer.
Definition: net.h:662
const CAddress addr
Definition: net.h:698
std::vector< T > ConsumeBytes(size_t num_bytes)
T ConsumeIntegralInRange(T min, T max)
size_t ConsumeData(void *destination, size_t num_bytes)
Definition: net.h:30
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:258
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:272
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:336
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:239
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:45
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:353
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:362
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:197
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:100
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:94
std::optional< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:38
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:31
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:331
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:318
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:291
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:132
~FuzzedSock() override
Definition: net.cpp:85
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:304
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:79
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:219
RAII helper class that manages a socket.
Definition: sock.h:28
SOCKET m_socket
Contained socket.
Definition: sock.h:273
uint8_t Event
Definition: sock.h:148
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:218
#define INVALID_SOCKET
Definition: compat.h:53
unsigned int SOCKET
Definition: compat.h:43
Definition: init.h:25
std::string OnionToString(Span< const uint8_t > addr)
Definition: netaddress.cpp:570
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:92
Network
A network type.
Definition: netaddress.h:36
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:47
@ NET_IPV6
IPv6.
Definition: netaddress.h:44
@ NET_IPV4
IPv4.
Definition: netaddress.h:41
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:57
const char * name
Definition: rest.cpp:45
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:59
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:28
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:53
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:371
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:93
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:132
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:48
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:217
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:237
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:61
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:23
assert(!tx.IsCoinBase())
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
Definition: version.h:18