Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
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
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
26class CNode;
27
28CNetAddr 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},
40 NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_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
87CAddress 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
92template <typename P>
93P 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
135ssize_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
167ssize_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
235int 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
257int 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
277int 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 };
291 return -1;
292 }
293 return 0;
294}
295
296std::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 };
305 return std::unique_ptr<FuzzedSock>();
306 }
307 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
308}
309
310int 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
329int 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
342int 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
374bool 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
394bool 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
406bool FuzzedSock::IsConnected(std::string& errmsg) const
407{
409 return true;
410 }
411 errmsg = "disconnected at random by the fuzzer";
412 return false;
413}
414
415void 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}
int flags
A CService with information about it as peer.
Definition protocol.h:367
static constexpr SerParams V2_NETWORK
Definition protocol.h:409
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.
BIP155Network
BIP155 network ids recognized by this software.
Definition netaddress.h:263
Information about a peer.
Definition net.h:670
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:147
Fast randomness source.
Definition random.h:377
T ConsumeIntegralInRange(T min, T max)
size_t ConsumeData(void *destination, size_t num_bytes)
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition net.cpp:296
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition net.cpp:310
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
int Listen(int backlog) const override
listen(2) wrapper.
Definition net.cpp:277
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:394
bool IsConnected(std::string &errmsg) const override
Check if still connected.
Definition net.cpp:406
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition net.cpp:235
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition net.cpp:135
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition net.h:46
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition net.cpp:129
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:369
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition net.cpp:356
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition net.cpp:329
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:342
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition net.cpp:113
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition net.cpp:257
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:56
unsigned int SOCKET
Definition compat.h:46
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
static const int MIN_PEER_PROTO_VERSION
disconnect from peers older than this proto version
const char * name
Definition rest.cpp:49
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition net.cpp:87
P ConsumeDeserializationParams(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition net.cpp:93
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:415
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
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
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition util.h:57
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
constexpr ServiceFlags ALL_SERVICE_FLAGS[]
Definition net.h:94
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition time.h:23
assert(!tx.IsCoinBase())