pcp.cpp raw
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 void port_map_target_init()
28 {
29 LogInstance().DisableLogging();
30 }
31
32 FUZZ_TARGET(pcp_request_port_map, .init = port_map_target_init)
33 {
34 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
35 FakeSteadyClock steady_clock;
36
37 // Create a mocked socket between random (and potentially invalid) client and gateway addresses.
38 auto CreateSockOrig = CreateSock;
39 CreateSock = [&](int domain, int type, int protocol) {
40 if ((domain == AF_INET || domain == AF_INET6) && type == SOCK_DGRAM && protocol == IPPROTO_UDP) {
41 return std::make_unique<FuzzedSock>(fuzzed_data_provider, steady_clock);
42 }
43 return std::unique_ptr<FuzzedSock>();
44 };
45
46 // Perform the port mapping request. The mocked socket will return fuzzer-provided data.
47 const auto gateway_addr{ConsumeNetAddr(fuzzed_data_provider)};
48 const auto local_addr{ConsumeNetAddr(fuzzed_data_provider)};
49 const auto port{fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
50 const auto lifetime{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
51 CThreadInterrupt interrupt;
52 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 if (const MappingResult* mapping = std::get_if<MappingResult>(&res)) {
56 Assert(mapping);
57 Assert(mapping->internal.GetPort() == port);
58 mapping->ToString();
59 }
60
61 CreateSock = CreateSockOrig;
62 }
63
64 FUZZ_TARGET(natpmp_request_port_map, .init = port_map_target_init)
65 {
66 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
67 FakeSteadyClock steady_clock;
68
69 // Create a mocked socket between random (and potentially invalid) client and gateway addresses.
70 auto CreateSockOrig = CreateSock;
71 CreateSock = [&](int domain, int type, int protocol) {
72 if (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP) {
73 return std::make_unique<FuzzedSock>(fuzzed_data_provider, steady_clock);
74 }
75 return std::unique_ptr<FuzzedSock>();
76 };
77
78 // Perform the port mapping request. The mocked socket will return fuzzer-provided data.
79 const auto gateway_addr{ConsumeNetAddr(fuzzed_data_provider)};
80 const auto port{fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
81 const auto lifetime{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
82 CThreadInterrupt interrupt;
83 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 if (const MappingResult* mapping = std::get_if<MappingResult>(&res)) {
87 Assert(mapping);
88 Assert(mapping->internal.GetPort() == port);
89 mapping->ToString();
90 }
91
92 CreateSock = CreateSockOrig;
93 }
94