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
|