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