Bitcoin Core 28.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
142class FuzzedSock : public Sock
143{
145
151 mutable std::vector<uint8_t> m_peek_data;
152
158 const bool m_selectable;
159
160public:
161 explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
162
163 ~FuzzedSock() override;
164
165 FuzzedSock& operator=(Sock&& other) override;
166
167 ssize_t Send(const void* data, size_t len, int flags) const override;
168
169 ssize_t Recv(void* buf, size_t len, int flags) const override;
170
171 int Connect(const sockaddr*, socklen_t) const override;
172
173 int Bind(const sockaddr*, socklen_t) const override;
174
175 int Listen(int backlog) const override;
176
177 std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
178
179 int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
180
181 int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
182
183 int GetSockName(sockaddr* name, socklen_t* name_len) const override;
184
185 bool SetNonBlocking() const override;
186
187 bool IsSelectable() const override;
188
189 bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
190
191 bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
192
193 bool IsConnected(std::string& errmsg) const override;
194};
195
196[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
197{
198 return FuzzedSock{fuzzed_data_provider};
199}
200
201[[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
202{
203 std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
204 if (!SanityCheckASMap(asmap, 128)) asmap.clear();
205 return NetGroupManager(asmap);
206}
207
208inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
209{
210 return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
211}
212
213inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
214{
215 return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
216}
217
218CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
219
220template <bool ReturnUniquePtr = false>
221auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
222{
223 const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
224 const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
225 const CAddress address = ConsumeAddress(fuzzed_data_provider);
226 const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
227 const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
228 const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
229 const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
230 const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
231 const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
232 NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
233 if constexpr (ReturnUniquePtr) {
234 return std::make_unique<CNode>(node_id,
235 sock,
236 address,
237 keyed_net_group,
238 local_host_nonce,
239 addr_bind,
240 addr_name,
241 conn_type,
242 inbound_onion,
243 CNodeOptions{ .permission_flags = permission_flags });
244 } else {
245 return CNode{node_id,
246 sock,
247 address,
248 keyed_net_group,
249 local_host_nonce,
250 addr_bind,
251 addr_name,
252 conn_type,
253 inbound_onion,
254 CNodeOptions{ .permission_flags = permission_flags }};
255 }
256}
257inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
258
260
261#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 flags
Definition: bitcoin-tx.cpp:536
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:673
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:377
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:158
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:151
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:144
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
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
Definition: net.h:995
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:97
NetPermissionFlags
const char * name
Definition: rest.cpp:49
NetPermissionFlags permission_flags
Definition: net.h:664
#define LOCK2(cs1, cs2)
Definition: sync.h:258
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
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:213
CSubNet ConsumeSubNet(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:208
NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.h:201
std::unique_ptr< CNode > ConsumeNodeAsUniquePtr(FuzzedDataProvider &fdp, const std::optional< NodeId > &node_id_in=std::nullopt)
Definition: net.h:257
CNetAddr ConsumeNetAddr(FuzzedDataProvider &fuzzed_data_provider, FastRandomContext *rand=nullptr) noexcept
Create a CNetAddr.
Definition: net.cpp:28
auto ConsumeNode(FuzzedDataProvider &fuzzed_data_provider, const std::optional< NodeId > &node_id_in=std::nullopt) noexcept
Definition: net.h:221
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:87
FuzzedSock ConsumeSock(FuzzedDataProvider &fuzzed_data_provider)
Definition: net.h:196
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:117
constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]
Definition: net.h:104
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
bool SanityCheckASMap(const std::vector< bool > &asmap, int bits)
Definition: asmap.cpp:133