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 : 0 : [[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider)
84 : : {
85 : 0 : return FuzzedSock{fuzzed_data_provider};
86 : : }
87 : :
88 : 0 : inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
89 : : {
90 [ # # ][ # # ]: 0 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
91 : : }
92 : :
93 : 0 : inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
94 : : {
95 [ # # ][ # # ]: 0 : return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
96 : : }
97 : :
98 : : CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
99 : :
100 : : template <bool ReturnUniquePtr = false>
101 : 0 : auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
102 : : {
103 [ # # ][ # # ]: 0 : const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
104 [ # # ][ # # ]: 0 : const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
105 : 0 : const CAddress address = ConsumeAddress(fuzzed_data_provider);
106 [ # # ][ # # ]: 0 : const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
107 [ # # ][ # # ]: 0 : const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
108 : 0 : const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
109 [ # # ][ # # ]: 0 : const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
110 [ # # ][ # # ]: 0 : const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
111 [ # # ][ # # ]: 0 : const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
[ # # ][ # # ]
112 : 0 : NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
113 : : if constexpr (ReturnUniquePtr) {
114 [ # # ]: 0 : return std::make_unique<CNode>(node_id,
115 : : sock,
116 : : address,
117 : : keyed_net_group,
118 : : local_host_nonce,
119 : : addr_bind,
120 : : addr_name,
121 : : conn_type,
122 : : inbound_onion,
123 : 0 : CNodeOptions{ .permission_flags = permission_flags });
124 : : } else {
125 [ # # ][ # # ]: 0 : return CNode{node_id,
126 : 0 : sock,
127 : : address,
128 : 0 : keyed_net_group,
129 : 0 : local_host_nonce,
130 : : addr_bind,
131 : : addr_name,
132 : 0 : conn_type,
133 : 0 : inbound_onion,
134 : 0 : CNodeOptions{ .permission_flags = permission_flags }};
135 : : }
136 : 0 : }
137 : 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); }
138 : :
139 : : void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
140 : :
141 : : #endif // BITCOIN_TEST_FUZZ_UTIL_NET_H
|