Bitcoin Core  28.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()}
117 {
118 }
119 
121 {
122  // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
123  // close(m_socket) if m_socket is not INVALID_SOCKET.
124  // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
125  // theoretically may concide with a real opened file descriptor).
127 }
128 
130 {
131  assert(false && "Move of Sock into FuzzedSock not allowed.");
132  return *this;
133 }
134 
135 ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const
136 {
137  constexpr std::array send_errnos{
138  EACCES,
139  EAGAIN,
140  EALREADY,
141  EBADF,
142  ECONNRESET,
143  EDESTADDRREQ,
144  EFAULT,
145  EINTR,
146  EINVAL,
147  EISCONN,
148  EMSGSIZE,
149  ENOBUFS,
150  ENOMEM,
151  ENOTCONN,
152  ENOTSOCK,
153  EOPNOTSUPP,
154  EPIPE,
155  EWOULDBLOCK,
156  };
158  return len;
159  }
160  const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
161  if (r == -1) {
163  }
164  return r;
165 }
166 
167 ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
168 {
169  // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted
170  // SetFuzzedErrNo() will always return the first element and we want to avoid Recv()
171  // returning -1 and setting errno to EAGAIN repeatedly.
172  constexpr std::array recv_errnos{
173  ECONNREFUSED,
174  EAGAIN,
175  EBADF,
176  EFAULT,
177  EINTR,
178  EINVAL,
179  ENOMEM,
180  ENOTCONN,
181  ENOTSOCK,
182  EWOULDBLOCK,
183  };
184  assert(buf != nullptr || len == 0);
185 
186  // Do the latency before any of the "return" statements.
187  if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
188  std::this_thread::sleep_for(std::chrono::milliseconds{2});
189  }
190 
191  if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
192  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
193  if (r == -1) {
195  }
196  return r;
197  }
198 
199  size_t copied_so_far{0};
200 
201  if (!m_peek_data.empty()) {
202  // `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.
203  const size_t copy_len{std::min(len, m_peek_data.size())};
204  std::memcpy(buf, m_peek_data.data(), copy_len);
205  copied_so_far += copy_len;
206  if ((flags & MSG_PEEK) == 0) {
207  m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);
208  }
209  }
210 
211  if (copied_so_far == len) {
212  return copied_so_far;
213  }
214 
215  auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);
216  if (new_data.empty()) return copied_so_far;
217 
218  std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());
219  copied_so_far += new_data.size();
220 
221  if ((flags & MSG_PEEK) != 0) {
222  m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());
223  }
224 
225  if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {
226  return copied_so_far;
227  }
228 
229  // Pad to len bytes.
230  std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);
231 
232  return len;
233 }
234 
235 int FuzzedSock::Connect(const sockaddr*, socklen_t) const
236 {
237  // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
238  // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
239  // returning -1 and setting errno to EAGAIN repeatedly.
240  constexpr std::array connect_errnos{
241  ECONNREFUSED,
242  EAGAIN,
243  ECONNRESET,
244  EHOSTUNREACH,
245  EINPROGRESS,
246  EINTR,
247  ENETUNREACH,
248  ETIMEDOUT,
249  };
251  SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
252  return -1;
253  }
254  return 0;
255 }
256 
257 int FuzzedSock::Bind(const sockaddr*, socklen_t) const
258 {
259  // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
260  // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
261  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
262  // repeatedly because proper code should retry on temporary errors, leading to an
263  // infinite loop.
264  constexpr std::array bind_errnos{
265  EACCES,
266  EADDRINUSE,
267  EADDRNOTAVAIL,
268  EAGAIN,
269  };
272  return -1;
273  }
274  return 0;
275 }
276 
277 int FuzzedSock::Listen(int) const
278 {
279  // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
280  // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
281  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
282  // repeatedly because proper code should retry on temporary errors, leading to an
283  // infinite loop.
284  constexpr std::array listen_errnos{
285  EADDRINUSE,
286  EINVAL,
287  EOPNOTSUPP,
288  };
290  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
291  return -1;
292  }
293  return 0;
294 }
295 
296 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
297 {
298  constexpr std::array accept_errnos{
299  ECONNABORTED,
300  EINTR,
301  ENOMEM,
302  };
304  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
305  return std::unique_ptr<FuzzedSock>();
306  }
307  return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
308 }
309 
310 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
311 {
312  constexpr std::array getsockopt_errnos{
313  ENOMEM,
314  ENOBUFS,
315  };
317  SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
318  return -1;
319  }
320  if (opt_val == nullptr) {
321  return 0;
322  }
323  std::memcpy(opt_val,
325  *opt_len);
326  return 0;
327 }
328 
329 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
330 {
331  constexpr std::array setsockopt_errnos{
332  ENOMEM,
333  ENOBUFS,
334  };
336  SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
337  return -1;
338  }
339  return 0;
340 }
341 
342 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
343 {
344  constexpr std::array getsockname_errnos{
345  ECONNRESET,
346  ENOBUFS,
347  };
349  SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
350  return -1;
351  }
352  *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
353  return 0;
354 }
355 
357 {
358  constexpr std::array setnonblocking_errnos{
359  EBADF,
360  EPERM,
361  };
363  SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
364  return false;
365  }
366  return true;
367 }
368 
370 {
371  return m_selectable;
372 }
373 
374 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
375 {
376  constexpr std::array wait_errnos{
377  EBADF,
378  EINTR,
379  EINVAL,
380  };
383  return false;
384  }
385  if (occurred != nullptr) {
386  // We simulate the requested event as occurred when ConsumeBool()
387  // returns false. This avoids simulating endless waiting if the
388  // FuzzedDataProvider runs out of data.
389  *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
390  }
391  return true;
392 }
393 
394 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
395 {
396  for (auto& [sock, events] : events_per_sock) {
397  (void)sock;
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  events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
402  }
403  return true;
404 }
405 
406 bool FuzzedSock::IsConnected(std::string& errmsg) const
407 {
409  return true;
410  }
411  errmsg = "disconnected at random by the fuzzer";
412  return false;
413 }
414 
415 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
416 {
417  connman.Handshake(node,
418  /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
419  /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
420  /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
421  /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
422  /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
423 }
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:238
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:415
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:129
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:131
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:46
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:329
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:406
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:167
#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
Definition: net.h:37
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:135
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:23
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:94
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:374
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:101
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:120
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:310
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:296
size_t ConsumeData(void *destination, size_t num_bytes)
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:235
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
int flags
Definition: bitcoin-tx.cpp:533
Network address.
Definition: netaddress.h:111
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:39
void resize(size_type n, value_type c=value_type{})
Definition: streams.h:183
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:394
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:218
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:356
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:53
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:342
Information about a peer.
Definition: net.h:669
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:369
CJDNS.
Definition: netaddress.h:49
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:257
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:277