Branch data Line data Source code
1 : : // Copyright (c) 2024-present 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 : : #include <test/fuzz/FuzzedDataProvider.h>
6 : : #include <test/fuzz/fuzz.h>
7 : : #include <test/fuzz/util.h>
8 : : #include <test/fuzz/util/net.h>
9 : : #include <test/util/time.h>
10 : :
11 : : #include <common/pcp.h>
12 : : #include <logging.h>
13 : : #include <util/check.h>
14 : : #include <util/threadinterrupt.h>
15 : :
16 : : using namespace std::literals;
17 : :
18 : : //! Fixed nonce to use in PCP port mapping requests.
19 : : constexpr PCPMappingNonce PCP_NONCE{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
20 : :
21 : : //! Number of attempts to request a NAT-PMP or PCP port mapping to the gateway.
22 : : constexpr int NUM_TRIES{5};
23 : :
24 : : //! Timeout for each attempt to request a port mapping.
25 : : constexpr std::chrono::duration TIMEOUT{100ms};
26 : :
27 : 2 : void port_map_target_init()
28 : : {
29 : 2 : LogInstance().DisableLogging();
30 : 2 : }
31 : :
32 [ + - ]: 756 : FUZZ_TARGET(pcp_request_port_map, .init = port_map_target_init)
33 : : {
34 : 282 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
35 : 282 : FakeSteadyClock steady_clock;
36 : :
37 : : // Create a mocked socket between random (and potentially invalid) client and gateway addresses.
38 [ + - ]: 282 : auto CreateSockOrig = CreateSock;
39 : 512 : CreateSock = [&](int domain, int type, int protocol) {
40 [ + - + - ]: 230 : if ((domain == AF_INET || domain == AF_INET6) && type == SOCK_DGRAM && protocol == IPPROTO_UDP) {
41 : 230 : return std::make_unique<FuzzedSock>(fuzzed_data_provider, steady_clock);
42 : : }
43 : 0 : return std::unique_ptr<FuzzedSock>();
44 : 282 : };
45 : :
46 : : // Perform the port mapping request. The mocked socket will return fuzzer-provided data.
47 : 282 : const auto gateway_addr{ConsumeNetAddr(fuzzed_data_provider)};
48 : 282 : const auto local_addr{ConsumeNetAddr(fuzzed_data_provider)};
49 : 282 : const auto port{fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
50 : 282 : const auto lifetime{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
51 [ + - ]: 282 : CThreadInterrupt interrupt;
52 [ + - ]: 282 : const auto res{PCPRequestPortMap(PCP_NONCE, gateway_addr, local_addr, port, lifetime, interrupt, NUM_TRIES, TIMEOUT)};
53 : :
54 : : // In case of success the mapping must be consistent with the request.
55 [ + + ]: 282 : if (const MappingResult* mapping = std::get_if<MappingResult>(&res)) {
56 [ + - ]: 58 : Assert(mapping);
57 [ + - - + ]: 58 : Assert(mapping->internal.GetPort() == port);
58 [ + - ]: 116 : mapping->ToString();
59 : : }
60 : :
61 [ + - ]: 282 : CreateSock = CreateSockOrig;
62 : 282 : }
63 : :
64 [ + - ]: 695 : FUZZ_TARGET(natpmp_request_port_map, .init = port_map_target_init)
65 : : {
66 : 221 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
67 : 221 : FakeSteadyClock steady_clock;
68 : :
69 : : // Create a mocked socket between random (and potentially invalid) client and gateway addresses.
70 [ + - ]: 221 : auto CreateSockOrig = CreateSock;
71 : 360 : CreateSock = [&](int domain, int type, int protocol) {
72 [ + - + - ]: 139 : if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) {
73 : 139 : return std::make_unique<FuzzedSock>(fuzzed_data_provider, steady_clock);
74 : : }
75 : 0 : return std::unique_ptr<FuzzedSock>();
76 : 221 : };
77 : :
78 : : // Perform the port mapping request. The mocked socket will return fuzzer-provided data.
79 : 221 : const auto gateway_addr{ConsumeNetAddr(fuzzed_data_provider)};
80 : 221 : const auto port{fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
81 : 221 : const auto lifetime{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
82 [ + - ]: 221 : CThreadInterrupt interrupt;
83 [ + - ]: 221 : const auto res{NATPMPRequestPortMap(gateway_addr, port, lifetime, interrupt, NUM_TRIES, TIMEOUT)};
84 : :
85 : : // In case of success the mapping must be consistent with the request.
86 [ + + ]: 221 : if (const MappingResult* mapping = std::get_if<MappingResult>(&res)) {
87 [ + - ]: 18 : Assert(mapping);
88 [ + - - + ]: 18 : Assert(mapping->internal.GetPort() == port);
89 [ + - ]: 36 : mapping->ToString();
90 : : }
91 : :
92 [ + - ]: 221 : CreateSock = CreateSockOrig;
93 : 221 : }
|