Bitcoin Core  26.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>
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  if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
186  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
187  if (r == -1) {
189  }
190  return r;
191  }
192  std::vector<uint8_t> random_bytes;
193  bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
194  if (m_peek_data.has_value()) {
195  // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
196  random_bytes.assign({m_peek_data.value()});
197  if ((flags & MSG_PEEK) == 0) {
198  m_peek_data.reset();
199  }
200  pad_to_len_bytes = false;
201  } else if ((flags & MSG_PEEK) != 0) {
202  // New call with `MSG_PEEK`.
203  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
204  if (!random_bytes.empty()) {
205  m_peek_data = random_bytes[0];
206  pad_to_len_bytes = false;
207  }
208  } else {
209  random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
211  }
212  if (random_bytes.empty()) {
213  const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
214  if (r == -1) {
216  }
217  return r;
218  }
219  std::memcpy(buf, random_bytes.data(), random_bytes.size());
220  if (pad_to_len_bytes) {
221  if (len > random_bytes.size()) {
222  std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
223  }
224  return len;
225  }
226  if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
227  std::this_thread::sleep_for(std::chrono::milliseconds{2});
228  }
229  return random_bytes.size();
230 }
231 
232 int FuzzedSock::Connect(const sockaddr*, socklen_t) const
233 {
234  // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted
235  // SetFuzzedErrNo() will always return the first element and we want to avoid Connect()
236  // returning -1 and setting errno to EAGAIN repeatedly.
237  constexpr std::array connect_errnos{
238  ECONNREFUSED,
239  EAGAIN,
240  ECONNRESET,
241  EHOSTUNREACH,
242  EINPROGRESS,
243  EINTR,
244  ENETUNREACH,
245  ETIMEDOUT,
246  };
248  SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos);
249  return -1;
250  }
251  return 0;
252 }
253 
254 int FuzzedSock::Bind(const sockaddr*, socklen_t) const
255 {
256  // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted
257  // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to
258  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
259  // repeatedly because proper code should retry on temporary errors, leading to an
260  // infinite loop.
261  constexpr std::array bind_errnos{
262  EACCES,
263  EADDRINUSE,
264  EADDRNOTAVAIL,
265  EAGAIN,
266  };
269  return -1;
270  }
271  return 0;
272 }
273 
274 int FuzzedSock::Listen(int) const
275 {
276  // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted
277  // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to
278  // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN)
279  // repeatedly because proper code should retry on temporary errors, leading to an
280  // infinite loop.
281  constexpr std::array listen_errnos{
282  EADDRINUSE,
283  EINVAL,
284  EOPNOTSUPP,
285  };
287  SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos);
288  return -1;
289  }
290  return 0;
291 }
292 
293 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const
294 {
295  constexpr std::array accept_errnos{
296  ECONNABORTED,
297  EINTR,
298  ENOMEM,
299  };
301  SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
302  return std::unique_ptr<FuzzedSock>();
303  }
304  return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
305 }
306 
307 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
308 {
309  constexpr std::array getsockopt_errnos{
310  ENOMEM,
311  ENOBUFS,
312  };
314  SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
315  return -1;
316  }
317  if (opt_val == nullptr) {
318  return 0;
319  }
320  std::memcpy(opt_val,
322  *opt_len);
323  return 0;
324 }
325 
326 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const
327 {
328  constexpr std::array setsockopt_errnos{
329  ENOMEM,
330  ENOBUFS,
331  };
333  SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos);
334  return -1;
335  }
336  return 0;
337 }
338 
339 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const
340 {
341  constexpr std::array getsockname_errnos{
342  ECONNRESET,
343  ENOBUFS,
344  };
346  SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos);
347  return -1;
348  }
349  *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len);
350  return 0;
351 }
352 
354 {
355  constexpr std::array setnonblocking_errnos{
356  EBADF,
357  EPERM,
358  };
360  SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos);
361  return false;
362  }
363  return true;
364 }
365 
367 {
368  return m_selectable;
369 }
370 
371 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
372 {
373  constexpr std::array wait_errnos{
374  EBADF,
375  EINTR,
376  EINVAL,
377  };
380  return false;
381  }
382  if (occurred != nullptr) {
383  *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
384  }
385  return true;
386 }
387 
388 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
389 {
390  for (auto& [sock, events] : events_per_sock) {
391  (void)sock;
392  events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
393  }
394  return true;
395 }
396 
397 bool FuzzedSock::IsConnected(std::string& errmsg) const
398 {
400  return true;
401  }
402  errmsg = "disconnected at random by the fuzzer";
403  return false;
404 }
405 
406 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
407 {
408  connman.Handshake(node,
409  /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
410  /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
411  /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
412  /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
413  /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
414 }
int flags
Definition: bitcoin-tx.cpp:530
A CService with information about it as peer.
Definition: protocol.h:332
static constexpr SerParams V2_NETWORK
Definition: protocol.h:374
Network address.
Definition: netaddress.h:112
@ V2
BIP155 encoding.
bool SetInternal(const std::string &name)
Create an "internal" address that represents a name or FQDN.
Definition: netaddress.cpp:169
BIP155Network
BIP155 network ids recognized by this software.
Definition: netaddress.h:263
Information about a peer.
Definition: net.h:677
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
Fast randomness source.
Definition: random.h:144
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:38
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:293
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:307
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:371
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:274
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:53
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:388
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:397
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:232
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:135
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:129
std::optional< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:46
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:39
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:366
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:353
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:326
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:167
~FuzzedSock() override
Definition: net.cpp:120
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:339
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:113
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:254
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:27
SOCKET m_socket
Contained socket.
Definition: sock.h:275
uint8_t Event
Definition: sock.h:138
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
#define INVALID_SOCKET
Definition: compat.h:49
unsigned int SOCKET
Definition: compat.h:39
@ I2P
Definition: logging.h:63
Definition: init.h:25
static constexpr uint8_t CJDNS_PREFIX
All CJDNS addresses start with 0xFC.
Definition: netaddress.h:82
static constexpr size_t ADDR_CJDNS_SIZE
Size of CJDNS address (in bytes).
Definition: netaddress.h:98
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:92
static constexpr size_t ADDR_I2P_SIZE
Size of I2P address (in bytes).
Definition: netaddress.h:95
static constexpr size_t ADDR_IPV4_SIZE
Size of IPv4 address (in bytes).
Definition: netaddress.h:85
Network
A network type.
Definition: netaddress.h:32
@ NET_I2P
I2P.
Definition: netaddress.h:46
@ NET_CJDNS
CJDNS.
Definition: netaddress.h:49
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:43
@ NET_IPV6
IPv6.
Definition: netaddress.h:40
@ NET_IPV4
IPv4.
Definition: netaddress.h:37
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:53
static constexpr size_t ADDR_IPV6_SIZE
Size of IPv6 address (in bytes).
Definition: netaddress.h:88
@ IPV4
Definition: netbase.cpp:247
@ IPV6
Definition: netbase.cpp:249
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
const char * name
Definition: rest.cpp:49
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:93
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:87
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand) noexcept
Create a CNetAddr.
Definition: net.cpp:28
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:406
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:101
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:131
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.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:218
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
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition: net.h:89
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:23
assert(!tx.IsCoinBase())