Branch data Line data Source code
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 <net.h>
9 : : #include <net_permissions.h>
10 : : #include <netaddress.h>
11 : : #include <node/connection_types.h>
12 : : #include <node/eviction.h>
13 : : #include <protocol.h>
14 : : #include <test/fuzz/FuzzedDataProvider.h>
15 : : #include <test/fuzz/util.h>
16 : : #include <test/util/net.h>
17 : : #include <threadsafety.h>
18 : : #include <util/sock.h>
19 : :
20 : : #include <chrono>
21 : : #include <cstdint>
22 : : #include <limits>
23 : : #include <memory>
24 : : #include <optional>
25 : : #include <string>
26 : :
27 : : /**
28 : : * Create a CNetAddr. It may have `addr.IsValid() == false`.
29 : : * @param[in,out] fuzzed_data_provider Take data for the address from this, if `rand` is `nullptr`.
30 : : * @param[in,out] rand If not nullptr, take data from it instead of from `fuzzed_data_provider`.
31 : : * Prefer generating addresses using `fuzzed_data_provider` because it is not uniform. Only use
32 : : * `rand` if `fuzzed_data_provider` is exhausted or its data is needed for other things.
33 : : * @return a "random" network address.
34 : : */
35 : : CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand = nullptr) noexcept;
36 : :
37 : : class FuzzedSock : public Sock
38 : : {
39 : : FuzzedDataProvider& m_fuzzed_data_provider;
40 : :
41 : : /**
42 : : * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
43 : : * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
44 : : * `Recv()` call we must return the same data, thus we remember it here.
45 : : */
46 : : mutable std::vector<uint8_t> m_peek_data;
47 : :
48 : : /**
49 : : * Whether to pretend that the socket is select(2)-able. This is randomly set in the
50 : : * constructor. It should remain constant so that repeated calls to `IsSelectable()`
51 : : * return the same value.
52 : : */
53 : : const bool m_selectable;
54 : :
55 : : public:
56 : : explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
57 : :
58 : : ~FuzzedSock() override;
59 : :
60 : : FuzzedSock& operator=(Sock&& other) override;
61 : :
62 : : ssize_t Send(const void* data, size_t len, int flags) const override;
63 : :
64 : : ssize_t Recv(void* buf, size_t len, int flags) const override;
65 : :
66 : : int Connect(const sockaddr*, socklen_t) const override;
67 : :
68 : : int Bind(const sockaddr*, socklen_t) const override;
69 : :
70 : : int Listen(int backlog) const override;
71 : :
72 : : std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
73 : :
74 : : int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
75 : :
76 : : int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
77 : :
78 : : int GetSockName(sockaddr* name, socklen_t* name_len) const override;
79 : :
80 : : bool SetNonBlocking() const override;
81 : :
82 : : bool IsSelectable() const override;
83 : :
84 : : bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
85 : :
86 : : bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
87 : :
88 : : bool IsConnected(std::string& errmsg) const override;
89 : : };
90 : :
91 : 0 : [[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
92 : : {
93 [ # # ]: 0 : return FuzzedSock{fuzzed_data_provider};
94 : : }
95 : :
96 : 0 : inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
97 : : {
98 : 0 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
99 : : }
100 : :
101 : 0 : inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
102 : : {
103 : 0 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
104 : : }
105 : :
106 : : CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
107 : :
108 : : template <bool ReturnUniquePtr = false>
109 : 0 : auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
110 : : {
111 [ # # ]: 0 : const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
112 : 0 : const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
113 : 0 : const CAddress address = ConsumeAddress(fuzzed_data_provider);
114 : 0 : const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
115 : 0 : const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
116 : 0 : const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
117 : 0 : const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
118 : 0 : const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
119 [ # # # # ]: 0 : const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
120 : 0 : NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
121 : : if constexpr (ReturnUniquePtr) {
122 : : return std::make_unique<CNode>(node_id,
123 : : sock,
124 : : address,
125 : : keyed_net_group,
126 : : local_host_nonce,
127 : : addr_bind,
128 : : addr_name,
129 : : conn_type,
130 : : inbound_onion,
131 : 0 : CNodeOptions{ .permission_flags = permission_flags });
132 : : } else {
133 : 0 : return CNode{node_id,
134 : : sock,
135 : : address,
136 : : keyed_net_group,
137 : : local_host_nonce,
138 : : addr_bind,
139 : : addr_name,
140 : : conn_type,
141 : : inbound_onion,
142 [ # # # # ]: 0 : CNodeOptions{ .permission_flags = permission_flags }};
143 : : }
144 [ # # ]: 0 : }
145 : 0 : inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
146 : :
147 : : void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
148 : :
149 : : #endif // BITCOIN_TEST_FUZZ_UTIL_NET_H
|