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 
59  : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()}
60 {
62 }
63 
65 {
66  // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
67  // close(m_socket) if m_socket is not INVALID_SOCKET.
68  // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
69  // theoretically may concide with a real opened file descriptor).
71 }
72 
74 {
75  assert(false && "Move of Sock into FuzzedSock not allowed.");
76  return *this;
77 }
78 
79 ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
80 {
81  constexpr std::array send_errnos{
82  EACCES,
83  EAGAIN,
84  EALREADY,
85  EBADF,
86  ECONNRESET,
87  EDESTADDRREQ,
88  EFAULT,
89  EINTR,
90  EINVAL,
91  EISCONN,
92  EMSGSIZE,
93  ENOBUFS,
94  ENOMEM,
95  ENOTCONN,
96  ENOTSOCK,
97  EOPNOTSUPP,
98  EPIPE,
99  EWOULDBLOCK,
100  };
102  return len;
103  }
104  const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
105  if (r == -1) {
107  }
108  return r;
109 }
110 
111 ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
112 {
113  // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
114  // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
115  // returning -1 and setting errno to EAGAIN repeatedly.
116  constexpr std::array recv_errnos{
117  ECONNREFUSED,
118  EAGAIN,
119  EBADF,
120  EFAULT,
121  EINTR,
122  EINVAL,
123  ENOMEM,
124  ENOTCONN,
125  ENOTSOCK,
126  EWOULDBLOCK,
127  };
128  assert(buf != nullptr || len == 0);
129  if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
130  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
131  if (r == -1) {
133  }
134  return r;
135  }
136  std::vector<uint8_t> random_bytes;
137  bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
138  if (m_peek_data.has_value()) {
139  // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
140  random_bytes.assign({m_peek_data.value()});
141  if ((flags & MSG_PEEK) == 0) {
142  m_peek_data.reset();
143  }
144  pad_to_len_bytes = false;
145  } else if ((flags & MSG_PEEK) != 0) {
146  // New call with `MSG_PEEK`.
147  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
148  if (!random_bytes.empty()) {
149  m_peek_data = random_bytes[0];
150  pad_to_len_bytes = false;
151  }
152  } else {
153  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
155  }
156  if (random_bytes.empty()) {
157  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
158  if (r == -1) {
160  }
161  return r;
162  }
163  std::memcpy(buf, random_bytes.data(), random_bytes.size());
164  if (pad_to_len_bytes) {
165  if (len > random_bytes.size()) {
166  std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
167  }
168  return len;
169  }
170  if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
171  std::this_thread::sleep_for(std::chrono::milliseconds{2});
172  }
173  return random_bytes.size();
174 }
175 
176 int FuzzedSock::Connect(const sockaddr*, socklen_t) const
177 {
178  // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
179  // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
180  // returning -1 and setting errno to EAGAIN repeatedly.
181  constexpr std::array connect_errnos{
182  ECONNREFUSED,
183  EAGAIN,
184  ECONNRESET,
185  EHOSTUNREACH,
186  EINPROGRESS,
187  EINTR,
188  ENETUNREACH,
189  ETIMEDOUT,
190  };
192  SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
193  return -1;
194  }
195  return 0;
196 }
197 
198 int FuzzedSock::Bind(const sockaddr*, socklen_t) const
199 {
200  // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
201  // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
202  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
203  // repeatedly because proper code should retry on temporary errors, leading to an
204  // infinite loop.
205  constexpr std::array bind_errnos{
206  EACCES,
207  EADDRINUSE,
208  EADDRNOTAVAIL,
209  EAGAIN,
210  };
213  return -1;
214  }
215  return 0;
216 }
217 
218 int FuzzedSock::Listen(int) const
219 {
220  // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
221  // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
222  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
223  // repeatedly because proper code should retry on temporary errors, leading to an
224  // infinite loop.
225  constexpr std::array listen_errnos{
226  EADDRINUSE,
227  EINVAL,
228  EOPNOTSUPP,
229  };
231  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
232  return -1;
233  }
234  return 0;
235 }
236 
237 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
238 {
239  constexpr std::array accept_errnos{
240  ECONNABORTED,
241  EINTR,
242  ENOMEM,
243  };
245  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
246  return std::unique_ptr<FuzzedSock>();
247  }
248  return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
249 }
250 
251 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
252 {
253  constexpr std::array getsockopt_errnos{
254  ENOMEM,
255  ENOBUFS,
256  };
258  SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
259  return -1;
260  }
261  if (opt_val == nullptr) {
262  return 0;
263  }
264  std::memcpy(opt_val,
266  *opt_len);
267  return 0;
268 }
269 
270 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
271 {
272  constexpr std::array setsockopt_errnos{
273  ENOMEM,
274  ENOBUFS,
275  };
277  SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
278  return -1;
279  }
280  return 0;
281 }
282 
283 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
284 {
285  constexpr std::array getsockname_errnos{
286  ECONNRESET,
287  ENOBUFS,
288  };
290  SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
291  return -1;
292  }
293  *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
294  return 0;
295 }
296 
298 {
299  constexpr std::array setnonblocking_errnos{
300  EBADF,
301  EPERM,
302  };
304  SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
305  return false;
306  }
307  return true;
308 }
309 
311 {
312  return m_selectable;
313 }
314 
315 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
316 {
317  constexpr std::array wait_errnos{
318  EBADF,
319  EINTR,
320  EINVAL,
321  };
324  return false;
325  }
326  if (occurred != nullptr) {
327  *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
328  }
329  return true;
330 }
331 
332 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
333 {
334  for (auto& [sock, events] : events_per_sock) {
335  (void)sock;
336  events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
337  }
338  return true;
339 }
340 
341 bool FuzzedSock::IsConnected(std::string& errmsg) const
342 {
344  return true;
345  }
346  errmsg = "disconnected at random by the fuzzer";
347  return false;
348 }
349 
350 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
351 {
352  connman.Handshake(node,
353  /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
354  /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
355  /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
356  /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
357  /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
358 }
int flags
Definition: bitcoin-tx.cpp:528
A CService with information about it as peer.
Definition: protocol.h:360
Network address.
Definition: netaddress.h:120
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
Definition: netaddress.cpp:208
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:360
const CAddress addr
Definition: net.h:395
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:237
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:251
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:315
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:218
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:332
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:341
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:176
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:79
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:73
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:310
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:297
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:270
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:111
~FuzzedSock() override
Definition: net.cpp:64
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:283
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:58
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:198
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:54
unsigned int SOCKET
Definition: compat.h:44
Definition: init.h:25
std::string OnionToString(Span< const uint8_t > addr)
Definition: netaddress.cpp:591
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:100
Network
A network type.
Definition: netaddress.h:44
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:55
@ NET_IPV6
IPv6.
Definition: netaddress.h:52
@ NET_IPV4
IPv4.
Definition: netaddress.h:49
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:65
const char * name
Definition: rest.cpp:45
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:350
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:110
std::vector< uint8_t > 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:212
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:193
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:57
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
assert(!tx.IsCoinBase())
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
Definition: version.h:18