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