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