Bitcoin Core  29.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>
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 <thread>
24 #include <vector>
25 
26 class CNode;
27 
28 CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand) noexcept
29 {
30  struct NetAux {
31  Network net;
33  size_t len;
34  };
35 
36  static constexpr std::array<NetAux, 6> nets{
37  NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE},
38  NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE},
39  NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE},
40  NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE},
41  NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE},
42  NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0},
43  };
44 
45  const size_t nets_index{rand == nullptr
46  ? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1)
47  : static_cast<size_t>(rand->randrange(nets.size()))};
48 
49  const auto& aux = nets[nets_index];
50 
51  CNetAddr addr;
52 
53  if (aux.net == Network::NET_INTERNAL) {
54  if (rand == nullptr) {
55  addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
56  } else {
57  const auto v = rand->randbytes(32);
58  addr.SetInternal(std::string{v.begin(), v.end()});
59  }
60  return addr;
61  }
62 
63  DataStream s;
64 
65  s << static_cast<uint8_t>(aux.bip155);
66 
67  std::vector<uint8_t> addr_bytes;
68  if (rand == nullptr) {
69  addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len);
70  addr_bytes.resize(aux.len);
71  } else {
72  addr_bytes = rand->randbytes(aux.len);
73  }
74  if (aux.net == NET_IPV6 && addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS.
75  addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do.
76  }
77  if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid().
78  addr_bytes[0] = CJDNS_PREFIX;
79  }
80  s << addr_bytes;
81 
82  s >> CAddress::V2_NETWORK(addr);
83 
84  return addr;
85 }
86 
87 CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
88 {
89  return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
90 }
91 
92 template <typename P>
93 P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept
94 {
95  constexpr std::array ADDR_ENCODINGS{
98  };
99  constexpr std::array ADDR_FORMATS{
102  };
103  if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {
104  return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};
105  }
106  if constexpr (std::is_same_v<P, CAddress::SerParams>) {
107  return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};
108  }
109 }
112 
114  : Sock{fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET)},
115  m_fuzzed_data_provider{fuzzed_data_provider},
116  m_selectable{fuzzed_data_provider.ConsumeBool()},
118 {
119  ElapseTime(std::chrono::seconds(0)); // start mocking the steady clock.
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 
131 void FuzzedSock::ElapseTime(std::chrono::milliseconds duration) const
132 {
133  m_time += duration;
135 }
136 
138 {
139  assert(false && "Move of Sock into FuzzedSock not allowed.");
140  return *this;
141 }
142 
143 ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
144 {
145  constexpr std::array send_errnos{
146  EACCES,
147  EAGAIN,
148  EALREADY,
149  EBADF,
150  ECONNRESET,
151  EDESTADDRREQ,
152  EFAULT,
153  EINTR,
154  EINVAL,
155  EISCONN,
156  EMSGSIZE,
157  ENOBUFS,
158  ENOMEM,
159  ENOTCONN,
160  ENOTSOCK,
161  EOPNOTSUPP,
162  EPIPE,
163  EWOULDBLOCK,
164  };
166  return len;
167  }
168  const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
169  if (r == -1) {
171  }
172  return r;
173 }
174 
175 ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
176 {
177  // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
178  // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
179  // returning -1 and setting errno to EAGAIN repeatedly.
180  constexpr std::array recv_errnos{
181  ECONNREFUSED,
182  EAGAIN,
183  EBADF,
184  EFAULT,
185  EINTR,
186  EINVAL,
187  ENOMEM,
188  ENOTCONN,
189  ENOTSOCK,
190  EWOULDBLOCK,
191  };
192  assert(buf != nullptr || len == 0);
193 
194  // Do the latency before any of the "return" statements.
195  if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
196  std::this_thread::sleep_for(std::chrono::milliseconds{2});
197  }
198 
199  if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
200  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
201  if (r == -1) {
203  }
204  return r;
205  }
206 
207  size_t copied_so_far{0};
208 
209  if (!m_peek_data.empty()) {
210  // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
211  const size_t copy_len{std::min(len, m_peek_data.size())};
212  std::memcpy(buf, m_peek_data.data(), copy_len);
213  copied_so_far += copy_len;
214  if ((flags & MSG_PEEK) == 0) {
215  m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
216  }
217  }
218 
219  if (copied_so_far == len) {
220  return copied_so_far;
221  }
222 
223  auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
224  if (new_data.empty()) return copied_so_far;
225 
226  std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
227  copied_so_far += new_data.size();
228 
229  if ((flags & MSG_PEEK) != 0) {
230  m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
231  }
232 
233  if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
234  return copied_so_far;
235  }
236 
237  // Pad to len bytes.
238  std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
239 
240  return len;
241 }
242 
243 int FuzzedSock::Connect(const sockaddr*, socklen_t) const
244 {
245  // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
246  // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
247  // returning -1 and setting errno to EAGAIN repeatedly.
248  constexpr std::array connect_errnos{
249  ECONNREFUSED,
250  EAGAIN,
251  ECONNRESET,
252  EHOSTUNREACH,
253  EINPROGRESS,
254  EINTR,
255  ENETUNREACH,
256  ETIMEDOUT,
257  };
259  SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
260  return -1;
261  }
262  return 0;
263 }
264 
265 int FuzzedSock::Bind(const sockaddr*, socklen_t) const
266 {
267  // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
268  // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
269  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
270  // repeatedly because proper code should retry on temporary errors, leading to an
271  // infinite loop.
272  constexpr std::array bind_errnos{
273  EACCES,
274  EADDRINUSE,
275  EADDRNOTAVAIL,
276  EAGAIN,
277  };
280  return -1;
281  }
282  return 0;
283 }
284 
285 int FuzzedSock::Listen(int) const
286 {
287  // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
288  // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
289  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
290  // repeatedly because proper code should retry on temporary errors, leading to an
291  // infinite loop.
292  constexpr std::array listen_errnos{
293  EADDRINUSE,
294  EINVAL,
295  EOPNOTSUPP,
296  };
298  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
299  return -1;
300  }
301  return 0;
302 }
303 
304 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
305 {
306  constexpr std::array accept_errnos{
307  ECONNABORTED,
308  EINTR,
309  ENOMEM,
310  };
312  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
313  return std::unique_ptr<FuzzedSock>();
314  }
315  return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
316 }
317 
318 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
319 {
320  constexpr std::array getsockopt_errnos{
321  ENOMEM,
322  ENOBUFS,
323  };
325  SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
326  return -1;
327  }
328  if (opt_val == nullptr) {
329  return 0;
330  }
331  std::memcpy(opt_val,
333  *opt_len);
334  return 0;
335 }
336 
337 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
338 {
339  constexpr std::array setsockopt_errnos{
340  ENOMEM,
341  ENOBUFS,
342  };
344  SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
345  return -1;
346  }
347  return 0;
348 }
349 
350 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
351 {
352  constexpr std::array getsockname_errnos{
353  ECONNRESET,
354  ENOBUFS,
355  };
357  SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
358  return -1;
359  }
360  assert(name_len);
361  const auto bytes{ConsumeRandomLengthByteVector(m_fuzzed_data_provider, *name_len)};
362  if (bytes.size() < (int)sizeof(sockaddr)) return -1;
363  std::memcpy(name, bytes.data(), bytes.size());
364  *name_len = bytes.size();
365  return 0;
366 }
367 
369 {
370  constexpr std::array setnonblocking_errnos{
371  EBADF,
372  EPERM,
373  };
375  SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
376  return false;
377  }
378  return true;
379 }
380 
382 {
383  return m_selectable;
384 }
385 
386 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
387 {
388  constexpr std::array wait_errnos{
389  EBADF,
390  EINTR,
391  EINVAL,
392  };
395  return false;
396  }
397  if (occurred != nullptr) {
398  // We simulate the requested event as occurred when ConsumeBool()
399  // returns false. This avoids simulating endless waiting if the
400  // FuzzedDataProvider runs out of data.
401  *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
402  }
403  ElapseTime(timeout);
404  return true;
405 }
406 
407 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
408 {
409  for (auto& [sock, events] : events_per_sock) {
410  (void)sock;
411  // We simulate the requested event as occurred when ConsumeBool()
412  // returns false. This avoids simulating endless waiting if the
413  // FuzzedDataProvider runs out of data.
414  events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
415  }
416  ElapseTime(timeout);
417  return true;
418 }
419 
420 bool FuzzedSock::IsConnected(std::string& errmsg) const
421 {
423  return true;
424  }
425  errmsg = "disconnected at random by the fuzzer";
426  return false;
427 }
428 
429 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
430 {
431  auto successfully_connected = fuzzed_data_provider.ConsumeBool();
432  auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
433  auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
434  auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
435  auto relay_txs = fuzzed_data_provider.ConsumeBool();
436  connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
437 }
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:256
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:429
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:137
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:53
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:133
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:92
IPv4.
Definition: netaddress.h:37
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:151
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:85
SOCKET m_socket
Contained socket.
Definition: sock.h:275
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:337
std::chrono::milliseconds m_time
Used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:163
static void SetMockTime(std::chrono::milliseconds mock_time_in)
Set mock time for testing.
Definition: time.cpp:65
memcpy(result.begin(), stream.data(), stream.size())
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:420
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:175
#define INVALID_SOCKET
Definition: compat.h:56
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:46
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:143
static constexpr size_t ADDR_CJDNS_SIZE
Size of CJDNS address (in bytes).
Definition: netaddress.h:98
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:87
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:95
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:88
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:386
static constexpr size_t ADDR_I2P_SIZE
Size of I2P address (in bytes).
Definition: netaddress.h:95
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:49
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
BIP155Network
BIP155 network ids recognized by this software.
Definition: netaddress.h:263
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:223
Fast randomness source.
Definition: random.h:376
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:93
A CService with information about it as peer.
Definition: protocol.h:366
Network
A network type.
Definition: netaddress.h:32
~FuzzedSock() override
Definition: net.cpp:122
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:318
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:304
uint8_t Event
Definition: sock.h:138
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand) noexcept
Create a CNetAddr.
Definition: net.cpp:28
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:243
unsigned int SOCKET
Definition: compat.h:46
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:113
Definition: messages.h:20
static constexpr uint8_t CJDNS_PREFIX
All CJDNS addresses start with 0xFC.
Definition: netaddress.h:82
static constexpr std::chrono::milliseconds INITIAL_MOCK_TIME
Definition: time.h:41
int flags
Definition: bitcoin-tx.cpp:536
Network address.
Definition: netaddress.h:111
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:144
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:131
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:407
BIP155 encoding.
IPv6.
Definition: netaddress.h:40
TOR (v2 or v3)
Definition: netaddress.h:43
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:236
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:368
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:158
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:350
Information about a peer.
Definition: net.h:672
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:172
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:381
CJDNS.
Definition: netaddress.h:49
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:265
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:285