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