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 : : CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept;
28 : :
29 : : class FuzzedSock : public Sock
30 : : {
31 : : FuzzedDataProvider& m_fuzzed_data_provider;
32 : :
33 : : /**
34 : : * Data to return when `MSG_PEEK` is used as a `Recv()` flag.
35 : : * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next
36 : : * `Recv()` call we must return the same data, thus we remember it here.
37 : : */
38 : : mutable std::optional<uint8_t> m_peek_data;
39 : :
40 : : /**
41 : : * Whether to pretend that the socket is select(2)-able. This is randomly set in the
42 : : * constructor. It should remain constant so that repeated calls to `IsSelectable()`
43 : : * return the same value.
44 : : */
45 : : const bool m_selectable;
46 : :
47 : : public:
48 : : explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider);
49 : :
50 : : ~FuzzedSock() override;
51 : :
52 : : FuzzedSock& operator=(Sock&& other) override;
53 : :
54 : : ssize_t Send(const void* data, size_t len, int flags) const override;
55 : :
56 : : ssize_t Recv(void* buf, size_t len, int flags) const override;
57 : :
58 : : int Connect(const sockaddr*, socklen_t) const override;
59 : :
60 : : int Bind(const sockaddr*, socklen_t) const override;
61 : :
62 : : int Listen(int backlog) const override;
63 : :
64 : : std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
65 : :
66 : : int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
67 : :
68 : : int SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const override;
69 : :
70 : : int GetSockName(sockaddr* name, socklen_t* name_len) const override;
71 : :
72 : : bool SetNonBlocking() const override;
73 : :
74 : : bool IsSelectable() const override;
75 : :
76 : : bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override;
77 : :
78 : : bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
79 : :
80 : : bool IsConnected(std::string& errmsg) const override;
81 : : };
82 : :
83 : 73 : [[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
84 : : {
85 : 73 : return FuzzedSock{fuzzed_data_provider};
86 : : }
87 : :
88 : 15942 : inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
89 : : {
90 [ + - + - ]: 15942 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
91 : : }
92 : :
93 : 947159 : inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
94 : : {
95 [ + - + - ]: 947159 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
96 : : }
97 : :
98 : 78 : inline std::vector<CService> ConsumeServiceVector(FuzzedDataProvider& fuzzed_data_provider,
99 : : size_t max_vector_size) noexcept
100 : : {
101 : 78 : std::vector<CService> ret;
102 : 78 : const size_t size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
103 [ + - ]: 78 : ret.reserve(size);
104 [ + + ]: 263 : for (size_t i = 0; i < size; ++i) {
105 [ + - ]: 185 : ret.emplace_back(ConsumeNetAddr(fuzzed_data_provider),
106 [ + - ]: 185 : fuzzed_data_provider.ConsumeIntegral<uint16_t>());
107 : 185 : }
108 : 78 : return ret;
109 [ + - ]: 78 : }
110 : :
111 : : CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
112 : :
113 : : template <bool ReturnUniquePtr = false>
114 : 14855 : auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
115 : : {
116 [ + - + - ]: 14855 : const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
117 [ + - + - ]: 14855 : const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
118 : 14855 : const CAddress address = ConsumeAddress(fuzzed_data_provider);
119 [ + - + - ]: 14855 : const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
120 [ + - + - ]: 14855 : const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
121 : 14855 : const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
122 [ + - + - ]: 14855 : const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
123 [ + - + - ]: 14855 : const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
124 [ + + + - : 14855 : const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
+ + + - ]
125 : 14855 : NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
126 : : if constexpr (ReturnUniquePtr) {
127 [ + - ]: 13940 : return std::make_unique<CNode>(node_id,
128 : : sock,
129 : : address,
130 : : keyed_net_group,
131 : : local_host_nonce,
132 : : addr_bind,
133 : : addr_name,
134 : : conn_type,
135 : : inbound_onion,
136 : 27880 : CNodeOptions{ .permission_flags = permission_flags });
137 : : } else {
138 [ + - + - ]: 1830 : return CNode{node_id,
139 : 915 : sock,
140 : : address,
141 : 915 : keyed_net_group,
142 : 915 : local_host_nonce,
143 : : addr_bind,
144 : : addr_name,
145 : 915 : conn_type,
146 : 915 : inbound_onion,
147 : 1830 : CNodeOptions{ .permission_flags = permission_flags }};
148 : : }
149 : 14855 : }
150 : 13940 : inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
151 : :
152 : : void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
153 : :
154 : : #endif // BITCOIN_TEST_FUZZ_UTIL_NET_H
|