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