Bitcoin Core 30.99.0
P2P Digital Currency
net.h
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#ifndef BITCOIN_TEST_FUZZ_UTIL_NET_H
6#define BITCOIN_TEST_FUZZ_UTIL_NET_H
7
8#include <addrman.h>
9#include <addrman_impl.h>
10#include <net.h>
11#include <net_permissions.h>
12#include <netaddress.h>
14#include <node/eviction.h>
15#include <protocol.h>
17#include <test/fuzz/util.h>
18#include <test/util/net.h>
19#include <threadsafety.h>
20#include <util/asmap.h>
21#include <util/sock.h>
22
23#include <chrono>
24#include <cstdint>
25#include <limits>
26#include <memory>
27#include <optional>
28#include <string>
29
38CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand = nullptr) noexcept;
39
41{
42public:
43 explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider, int32_t check_ratio)
44 : AddrMan(netgroupman, /*deterministic=*/true, check_ratio)
45 {
46 WITH_LOCK(m_impl->cs, m_impl->insecure_rand.Reseed(ConsumeUInt256(fuzzed_data_provider)));
47 }
48
56 bool operator==(const AddrManDeterministic& other) const
57 {
58 LOCK2(m_impl->cs, other.m_impl->cs);
59
60 if (m_impl->mapInfo.size() != other.m_impl->mapInfo.size() || m_impl->nNew != other.m_impl->nNew ||
61 m_impl->nTried != other.m_impl->nTried) {
62 return false;
63 }
64
65 // Check that all values in `mapInfo` are equal to all values in `other.mapInfo`.
66 // Keys may be different.
67
68 auto addrinfo_hasher = [](const AddrInfo& a) {
69 CSipHasher hasher(0, 0);
70 auto addr_key = a.GetKey();
71 auto source_key = a.source.GetAddrBytes();
72 hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
73 hasher.Write(a.nAttempts);
74 hasher.Write(a.nRefCount);
75 hasher.Write(a.fInTried);
76 hasher.Write(a.GetNetwork());
77 hasher.Write(a.source.GetNetwork());
78 hasher.Write(addr_key.size());
79 hasher.Write(source_key.size());
80 hasher.Write(addr_key);
81 hasher.Write(source_key);
82 return (size_t)hasher.Finalize();
83 };
84
85 auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
86 return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
87 std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
88 };
89
90 using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
91
92 const size_t num_addresses{m_impl->mapInfo.size()};
93
94 Addresses addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
95 for (const auto& [id, addr] : m_impl->mapInfo) {
96 addresses.insert(addr);
97 }
98
99 Addresses other_addresses{num_addresses, addrinfo_hasher, addrinfo_eq};
100 for (const auto& [id, addr] : other.m_impl->mapInfo) {
101 other_addresses.insert(addr);
102 }
103
104 if (addresses != other_addresses) {
105 return false;
106 }
107
108 auto IdsReferToSameAddress = [&](nid_type id, nid_type other_id) EXCLUSIVE_LOCKS_REQUIRED(m_impl->cs, other.m_impl->cs) {
109 if (id == -1 && other_id == -1) {
110 return true;
111 }
112 if ((id == -1 && other_id != -1) || (id != -1 && other_id == -1)) {
113 return false;
114 }
115 return m_impl->mapInfo.at(id) == other.m_impl->mapInfo.at(other_id);
116 };
117
118 // Check that `vvNew` contains the same addresses as `other.vvNew`. Notice - `vvNew[i][j]`
119 // contains just an id and the address is to be found in `mapInfo.at(id)`. The ids
120 // themselves may differ between `vvNew` and `other.vvNew`.
121 for (size_t i = 0; i < ADDRMAN_NEW_BUCKET_COUNT; ++i) {
122 for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
123 if (!IdsReferToSameAddress(m_impl->vvNew[i][j], other.m_impl->vvNew[i][j])) {
124 return false;
125 }
126 }
127 }
128
129 // Same for `vvTried`.
130 for (size_t i = 0; i < ADDRMAN_TRIED_BUCKET_COUNT; ++i) {
131 for (size_t j = 0; j < ADDRMAN_BUCKET_SIZE; ++j) {
132 if (!IdsReferToSameAddress(m_impl->vvTried[i][j], other.m_impl->vvTried[i][j])) {
133 return false;
134 }
135 }
136 }
137
138 return true;
139 }
140};
141
143{
144public:
146
147 virtual void InitializeNode(const CNode&, ServiceFlags) override {}
148
149 virtual void FinalizeNode(const CNode&) override {}
150
151 virtual bool HasAllDesirableServiceFlags(ServiceFlags) const override { return m_fdp.ConsumeBool(); }
152
153 virtual bool ProcessMessages(CNode*, std::atomic<bool>&) override { return m_fdp.ConsumeBool(); }
154
155 virtual bool SendMessages(CNode*) override { return m_fdp.ConsumeBool(); }
156
157private:
159};
160
161class FuzzedSock : public Sock
162{
164
170 mutable std::vector<uint8_t> m_peek_data;
171
177 const bool m_selectable;
178
182 mutable std::chrono::milliseconds m_time;
183
187 void ElapseTime(std::chrono::milliseconds duration) const;
188
189public:
190 explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
191
192 ~FuzzedSock() override;
193
194 FuzzedSock& operator=(Sock&& other) override;
195
196 ssize_t Send(const void* data, size_t len, int flags) const override;
197
198 ssize_t Recv(void* buf, size_t len, int flags) const override;
199
200 int Connect(const sockaddr*, socklen_t) const override;
201
202 int Bind(const sockaddr*, socklen_t) const override;
203
204 int Listen(int backlog) const override;
205
206 std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
207
208 int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
209
210 int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
211
212 int GetSockName(sockaddr* name, socklen_t* name_len) const override;
213
214 bool SetNonBlocking() const override;
215
216 bool IsSelectable() const override;
217
218 bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
219
220 bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
221
222 bool IsConnected(std::string& errmsg) const override;
223};
224
225[[nodiscard]] inline FuzzedNetEvents ConsumeNetEvents(FuzzedDataProvider& fdp) noexcept
226{
227 return FuzzedNetEvents{fdp};
228}
229
230[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
231{
232 return FuzzedSock{fuzzed_data_provider};
233}
234
235[[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
236{
237 std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
238 if (!SanityCheckASMap(asmap, 128)) asmap.clear();
239 return NetGroupManager(asmap);
240}
241
242inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
243{
244 return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
245}
246
247inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
248{
249 return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
250}
251
252inline std::vector<CService> ConsumeServiceVector(FuzzedDataProvider& fuzzed_data_provider,
253 size_t max_vector_size = 5) noexcept
254{
255 std::vector<CService> ret;
256 const size_t size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
257 ret.reserve(size);
258 for (size_t i = 0; i < size; ++i) {
259 ret.emplace_back(ConsumeService(fuzzed_data_provider));
260 }
261 return ret;
262}
263
264CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
265
266template <bool ReturnUniquePtr = false>
267auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
268{
269 const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
270 const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
271 const CAddress address = ConsumeAddress(fuzzed_data_provider);
272 const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
273 const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
274 const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
275 const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
276 const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
277 const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
278 const uint64_t network_id = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
279
280 NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
281 if constexpr (ReturnUniquePtr) {
282 return std::make_unique<CNode>(node_id,
283 sock,
284 address,
285 keyed_net_group,
286 local_host_nonce,
287 addr_bind,
288 addr_name,
289 conn_type,
290 inbound_onion,
291 network_id,
292 CNodeOptions{ .permission_flags = permission_flags });
293 } else {
294 return CNode{node_id,
295 sock,
296 address,
297 keyed_net_group,
298 local_host_nonce,
299 addr_bind,
300 addr_name,
301 conn_type,
302 inbound_onion,
303 network_id,
304 CNodeOptions{ .permission_flags = permission_flags }};
305 }
306}
307inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
308
310
311#endif // BITCOIN_TEST_FUZZ_UTIL_NET_H
static constexpr int ADDRMAN_TRIED_BUCKET_COUNT
Definition: addrman_impl.h:27
static constexpr int ADDRMAN_BUCKET_SIZE
Definition: addrman_impl.h:33
int64_t nid_type
User-defined type for the internally used nIds This used to be int, making it feasible for attackers ...
Definition: addrman_impl.h:40
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman_impl.h:30
int ret
int flags
Definition: bitcoin-tx.cpp:529
Extended statistics about a CAddress.
Definition: addrman_impl.h:46
CNetAddr source
where knowledge about this address first came from
Definition: addrman_impl.h:55
bool fInTried
in tried set? (memory only)
Definition: addrman_impl.h:67
NodeSeconds m_last_success
last successful connection by us
Definition: addrman_impl.h:58
int nRefCount
reference count in new sets (memory only)
Definition: addrman_impl.h:64
int nAttempts
connection attempts since last successful attempt
Definition: addrman_impl.h:61
AddrManDeterministic(const NetGroupManager &netgroupman, FuzzedDataProvider &fuzzed_data_provider, int32_t check_ratio)
Definition: net.h:43
bool operator==(const AddrManDeterministic &other) const
Compare with another AddrMan.
Definition: net.h:56
Stochastic address manager.
Definition: addrman.h:89
const std::unique_ptr< AddrManImpl > m_impl
Definition: addrman.h:91
A CService with information about it as peer.
Definition: protocol.h:367
Network address.
Definition: netaddress.h:112
Information about a peer.
Definition: net.h:675
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:531
SipHash-2-4.
Definition: siphash.h:15
uint64_t Finalize() const
Compute the 64-bit SipHash-2-4 of the data written so far.
Definition: siphash.cpp:77
CSipHasher & Write(uint64_t data)
Hash a 64-bit integer worth of data It is treated as if this was the little-endian interpretation of ...
Definition: siphash.cpp:28
Fast randomness source.
Definition: random.h:386
T ConsumeIntegralInRange(T min, T max)
virtual bool SendMessages(CNode *) override
Send queued protocol messages to a given node.
Definition: net.h:155
virtual void InitializeNode(const CNode &, ServiceFlags) override
Initialize a peer (setup state)
Definition: net.h:147
virtual bool ProcessMessages(CNode *, std::atomic< bool > &) override
Process protocol messages received from a given node.
Definition: net.h:153
FuzzedDataProvider & m_fdp
Definition: net.h:158
FuzzedNetEvents(FuzzedDataProvider &fdp)
Definition: net.h:145
virtual bool HasAllDesirableServiceFlags(ServiceFlags) const override
Callback to determine whether the given set of service flags are sufficient for a peer to be "relevan...
Definition: net.h:151
virtual void FinalizeNode(const CNode &) override
Handle removal of a peer (clear state)
Definition: net.h:149
std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const override
accept(2) wrapper.
Definition: net.cpp:304
int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const override
getsockopt(2) wrapper.
Definition: net.cpp:345
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:413
int Listen(int backlog) const override
listen(2) wrapper.
Definition: net.cpp:285
const bool m_selectable
Whether to pretend that the socket is select(2)-able.
Definition: net.h:177
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:434
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 IsConnected(std::string &errmsg) const override
Check if still connected.
Definition: net.cpp:447
int Connect(const sockaddr *, socklen_t) const override
connect(2) wrapper.
Definition: net.cpp:243
ssize_t Send(const void *data, size_t len, int flags) const override
send(2) wrapper.
Definition: net.cpp:143
std::vector< uint8_t > m_peek_data
Data to return when MSG_PEEK is used as a Recv() flag.
Definition: net.h:170
FuzzedSock & operator=(Sock &&other) override
Move assignment operator, grab the socket from another object and close ours (if set).
Definition: net.cpp:137
FuzzedDataProvider & m_fuzzed_data_provider
Definition: net.h:163
bool IsSelectable() const override
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition: net.cpp:408
bool SetNonBlocking() const override
Set the non-blocking option on the socket.
Definition: net.cpp:395
int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const override
setsockopt(2) wrapper.
Definition: net.cpp:364
ssize_t Recv(void *buf, size_t len, int flags) const override
recv(2) wrapper.
Definition: net.cpp:175
~FuzzedSock() override
Definition: net.cpp:122
int GetSockName(sockaddr *name, socklen_t *name_len) const override
getsockname(2) wrapper.
Definition: net.cpp:377
std::chrono::milliseconds m_time
Used to mock the steady clock in methods waiting for a given duration.
Definition: net.h:182
FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.cpp:113
int Bind(const sockaddr *, socklen_t) const override
bind(2) wrapper.
Definition: net.cpp:265
Interface for message handling.
Definition: net.h:1015
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
Definition: net.h:1018
Netgroup manager.
Definition: netgroup.h:16
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:27
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
ConnectionType
Different types of connections to a peer.
@ INBOUND
Inbound connections are those initiated by a peer.
Definition: messages.h:20
int64_t NodeId
Definition: net.h:98
NetPermissionFlags
ServiceFlags
nServices flags
Definition: protocol.h:309
const char * name
Definition: rest.cpp:50
NetPermissionFlags permission_flags
Definition: net.h:666
#define LOCK2(cs1, cs2)
Definition: sync.h:260
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:290
void FillNode(FuzzedDataProvider &fuzzed_data_provider, ConnmanTestMsg &connman, CNode &node) noexcept
Definition: net.cpp:456
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:247
CSubNet ConsumeSubNet(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:242
NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:235
std::unique_ptr< CNode > ConsumeNodeAsUniquePtr(FuzzedDataProvider &fdp, const std::optional< NodeId > &node_id_in=std::nullopt)
Definition: net.h:307
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand=nullptr) noexcept
Create a CNetAddr.
Definition: net.cpp:28
std::vector< CService > ConsumeServiceVector(FuzzedDataProvider &fuzzed_data_provider, size_t max_vector_size=5) noexcept
Definition: net.h:252
auto ConsumeNode(FuzzedDataProvider &fuzzed_data_provider, const std::optional< NodeId > &node_id_in=std::nullopt) noexcept
Definition: net.h:267
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:87
FuzzedNetEvents ConsumeNetEvents(FuzzedDataProvider &fdp) noexcept
Definition: net.h:225
FuzzedSock ConsumeSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.h:230
WeakEnumType ConsumeWeakEnum(FuzzedDataProvider &fuzzed_data_provider, const WeakEnumType(&all_types)[size]) noexcept
Definition: util.h:133
std::vector< bool > ConsumeRandomLengthBitVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:68
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.h:171
constexpr ConnectionType ALL_CONNECTION_TYPES[]
Definition: net.h:139
constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]
Definition: net.h:126
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
bool SanityCheckASMap(const std::vector< bool > &asmap, int bits)
Definition: asmap.cpp:133