connman.cpp raw

   1  // Copyright (c) 2020-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 <addrman.h>
   6  #include <chainparams.h>
   7  #include <common/args.h>
   8  #include <net.h>
   9  #include <net_processing.h>
  10  #include <netaddress.h>
  11  #include <protocol.h>
  12  #include <test/fuzz/FuzzedDataProvider.h>
  13  #include <test/fuzz/fuzz.h>
  14  #include <test/fuzz/util.h>
  15  #include <test/fuzz/util/net.h>
  16  #include <test/fuzz/util/threadinterrupt.h>
  17  #include <test/util/setup_common.h>
  18  #include <test/util/time.h>
  19  #include <util/translation.h>
  20  
  21  #include <cstdint>
  22  #include <vector>
  23  
  24  namespace {
  25  const TestingSetup* g_setup;
  26  
  27  int32_t GetCheckRatio()
  28  {
  29      return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000);
  30  }
  31  
  32  } // namespace
  33  
  34  void initialize_connman()
  35  {
  36      static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
  37      g_setup = testing_setup.get();
  38  }
  39  
  40  FUZZ_TARGET(connman, .init = initialize_connman)
  41  {
  42      SeedRandomStateForTest(SeedRand::ZEROS);
  43      FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
  44      FakeNodeClock clock{ConsumeTime(fuzzed_data_provider)};
  45      FakeSteadyClock steady_clock;
  46      auto netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
  47      auto addr_man_ptr{std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio())};
  48      if (fuzzed_data_provider.ConsumeBool()) {
  49          const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
  50          DataStream ds{serialized_data};
  51          try {
  52              ds >> *addr_man_ptr;
  53          } catch (const std::ios_base::failure&) {
  54              addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider, GetCheckRatio());
  55          }
  56      }
  57      AddrManDeterministic& addr_man{*addr_man_ptr};
  58      auto net_events{ConsumeNetEvents(fuzzed_data_provider)};
  59  
  60      // Mock CreateSock() to create FuzzedSock.
  61      auto CreateSockOrig = CreateSock;
  62      CreateSock = [&fuzzed_data_provider, &steady_clock](int, int, int) {
  63          return std::make_unique<FuzzedSock>(fuzzed_data_provider, steady_clock);
  64      };
  65  
  66      // Mock g_dns_lookup() to return a fuzzed address.
  67      auto g_dns_lookup_orig = g_dns_lookup;
  68      g_dns_lookup = [&fuzzed_data_provider](const std::string&, bool) {
  69          return std::vector<CNetAddr>{ConsumeNetAddr(fuzzed_data_provider)};
  70      };
  71  
  72      ConnmanTestMsg connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
  73                       fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
  74                       addr_man,
  75                       netgroupman,
  76                       Params(),
  77                       fuzzed_data_provider.ConsumeBool(),
  78                       ConsumeThreadInterrupt(fuzzed_data_provider)};
  79  
  80      const uint64_t max_outbound_limit{fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
  81      CConnman::Options options;
  82      options.m_msgproc = &net_events;
  83      options.nMaxOutboundLimit = max_outbound_limit;
  84  
  85      const auto local_services{ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS)};
  86      options.m_local_services = local_services;
  87  
  88      const auto use_addrman_outgoing{fuzzed_data_provider.ConsumeBool()};
  89      options.m_use_addrman_outgoing = use_addrman_outgoing;
  90      options.m_max_automatic_connections = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1000);
  91  
  92      auto consume_whitelist = [&]() {
  93          std::vector<NetWhitelistPermissions> result(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3));
  94          for (auto& entry : result) {
  95              entry.m_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
  96              entry.m_subnet = ConsumeSubNet(fuzzed_data_provider);
  97          }
  98          return result;
  99      };
 100      options.vWhitelistedRangeIncoming = consume_whitelist();
 101      options.vWhitelistedRangeOutgoing = consume_whitelist();
 102  
 103      connman.Init(options);
 104  
 105      const uint64_t total_bytes_recv_initial{connman.GetTotalBytesRecv()};
 106      const uint64_t total_bytes_sent_initial{connman.GetTotalBytesSent()};
 107  
 108      CNetAddr random_netaddr;
 109      CAddress random_address;
 110      CNode random_node = ConsumeNode(fuzzed_data_provider, steady_clock);
 111      CSubNet random_subnet;
 112      std::string random_string;
 113      std::vector<NodeId> node_ids;
 114      std::vector<std::string> node_addr_names;
 115  
 116      LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) {
 117          CNode& p2p_node{*ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock).release()};
 118          // Simulate post-handshake state.
 119          p2p_node.fSuccessfullyConnected = true;
 120          connman.AddTestNode(p2p_node);
 121          node_ids.push_back(p2p_node.GetId());
 122          node_addr_names.push_back(p2p_node.m_addr_name);
 123      }
 124  
 125      LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
 126          CallOneOf(
 127              fuzzed_data_provider,
 128              [&] {
 129                  random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
 130              },
 131              [&] {
 132                  random_address = ConsumeAddress(fuzzed_data_provider);
 133              },
 134              [&] {
 135                  random_subnet = ConsumeSubNet(fuzzed_data_provider);
 136              },
 137              [&] {
 138                  random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
 139              },
 140              [&] {
 141                  const std::string& node_str = (!node_addr_names.empty() && fuzzed_data_provider.ConsumeBool())
 142                      ? PickValue(fuzzed_data_provider, node_addr_names)
 143                      : random_string;
 144                  const auto added_node_info{connman.GetAddedNodeInfo(/*include_connected=*/true)};
 145                  const auto add_node{connman.AddNode({node_str, /*use_v2transport=*/fuzzed_data_provider.ConsumeBool()})};
 146                  if (add_node) {
 147                      assert(!connman.AddNode({node_str, /*use_v2transport=*/fuzzed_data_provider.ConsumeBool()}));
 148                      assert(added_node_info.size() < connman.GetAddedNodeInfo(/*include_connected=*/true).size());
 149                      const auto remove{fuzzed_data_provider.ConsumeBool()};
 150                      if (remove) {
 151                          assert(connman.RemoveAddedNode(node_str));
 152                          assert(added_node_info.size() == connman.GetAddedNodeInfo(/*include_connected=*/true).size());
 153                      }
 154                  }
 155              },
 156              [&] {
 157                  (void)connman.RemoveAddedNode(random_string);
 158              },
 159              [&] {
 160                  connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
 161              },
 162              [&] {
 163                  connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
 164              },
 165              [&] {
 166                  connman.DisconnectNode(random_netaddr);
 167              },
 168              [&] {
 169                  connman.DisconnectNode(random_string);
 170              },
 171              [&] {
 172                  connman.DisconnectNode(random_subnet);
 173              },
 174              [&] {
 175                  NodeId id = node_ids.empty() || fuzzed_data_provider.ConsumeBool()
 176                      ? fuzzed_data_provider.ConsumeIntegral<NodeId>()
 177                      : PickValue(fuzzed_data_provider, node_ids);
 178                  (void)connman.ForNode(id, [&](CNode* pnode) {
 179                      (void)pnode->GetId();
 180                      (void)pnode->IsInboundConn();
 181                      (void)pnode->IsFullOutboundConn();
 182                      return true;
 183                  });
 184              },
 185              [&] {
 186                  auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
 187                  auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);
 188                  auto filtered = fuzzed_data_provider.ConsumeBool();
 189                  (void)connman.GetAddressesUnsafe(max_addresses, max_pct, /*network=*/std::nullopt, filtered);
 190              },
 191              [&] {
 192                  auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
 193                  auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 100);
 194                  (void)connman.GetAddresses(/*requestor=*/random_node, max_addresses, max_pct);
 195              },
 196              [&] {
 197                  (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
 198              },
 199              [&] {
 200                  (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({ConnectionDirection::None, ConnectionDirection::In, ConnectionDirection::Out, ConnectionDirection::Both}));
 201              },
 202              [&] {
 203                  (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
 204              },
 205              [&] {
 206                  CSerializedNetMsg serialized_net_msg;
 207                  serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::MESSAGE_TYPE_SIZE);
 208                  serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
 209                  connman.PushMessage(&random_node, std::move(serialized_net_msg));
 210              },
 211              [&] {
 212                  const auto set_active{fuzzed_data_provider.ConsumeBool()};
 213                  connman.SetNetworkActive(set_active);
 214                  assert(connman.GetNetworkActive() == set_active);
 215              },
 216              [&] {
 217                  connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
 218              },
 219              [&] {
 220                  const auto services{ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS)};
 221                  const auto before{connman.GetLocalServices()};
 222                  if (fuzzed_data_provider.ConsumeBool()) {
 223                      connman.AddLocalServices(services);
 224                      assert((connman.GetLocalServices() & services) == services);
 225                      // Restore by clearing only the bits that weren't already set.
 226                      connman.RemoveLocalServices(ServiceFlags(services & ~before));
 227                  } else {
 228                      connman.RemoveLocalServices(services);
 229                      assert((connman.GetLocalServices() & services) == 0);
 230                      // Restore by re-adding only the bits that were previously set.
 231                      connman.AddLocalServices(ServiceFlags(services & before));
 232                  }
 233                  assert(connman.GetLocalServices() == before);
 234              },
 235              [&] {
 236                  ConnectionType conn_type{
 237                      fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES)};
 238                  if (conn_type == ConnectionType::INBOUND) { // INBOUND is not allowed
 239                      conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
 240                  }
 241  
 242                  std::optional<Proxy> proxy_override;
 243                  if (conn_type == ConnectionType::PRIVATE_BROADCAST || fuzzed_data_provider.ConsumeBool()) {
 244                      proxy_override.emplace(ConsumeService(fuzzed_data_provider));
 245                  }
 246  
 247                  connman.OpenNetworkConnection(
 248                      /*addrConnect=*/random_address,
 249                      /*fCountFailure=*/fuzzed_data_provider.ConsumeBool(),
 250                      /*grant_outbound=*/{},
 251                      /*pszDest=*/fuzzed_data_provider.ConsumeBool() ? nullptr : random_string.c_str(),
 252                      /*conn_type=*/conn_type,
 253                      /*use_v2transport=*/fuzzed_data_provider.ConsumeBool(),
 254                      /*proxy_override=*/proxy_override);
 255              },
 256              [&] {
 257                  connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
 258                  const auto peer = ConsumeAddress(fuzzed_data_provider);
 259                  connman.CreateNodeFromAcceptedSocketPublic(
 260                      /*sock=*/CreateSock(AF_INET, SOCK_STREAM, IPPROTO_TCP),
 261                      /*permissions=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
 262                      /*addr_bind=*/ConsumeAddress(fuzzed_data_provider),
 263                      /*addr_peer=*/peer);
 264              },
 265              [&] {
 266                  CConnman::Options options;
 267  
 268                  options.vBinds = ConsumeServiceVector(fuzzed_data_provider);
 269  
 270                  options.vWhiteBinds = std::vector<NetWhitebindPermissions>{
 271                      fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 5)};
 272                  for (auto& wb : options.vWhiteBinds) {
 273                      wb.m_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
 274                      wb.m_service = ConsumeService(fuzzed_data_provider);
 275                  }
 276  
 277                  options.onion_binds = ConsumeServiceVector(fuzzed_data_provider);
 278  
 279                  options.bind_on_any = options.vBinds.empty() && options.vWhiteBinds.empty() &&
 280                                        options.onion_binds.empty();
 281  
 282                  connman.InitBindsPublic(options);
 283              },
 284              [&] {
 285                  connman.SocketHandlerPublic();
 286              });
 287      }
 288      connman.ForEachNode([](CNode* pnode) {
 289          (void)pnode->GetId();
 290          (void)pnode->IsInboundConn();
 291          (void)pnode->IsFullOutboundConn();
 292          (void)pnode->ConnectionTypeAsString();
 293      });
 294      (void)connman.GetAddedNodeInfo(/*include_connected=*/false);
 295      (void)connman.GetExtraFullOutboundCount();
 296      assert(connman.GetLocalServices() == local_services);
 297      assert(connman.GetMaxOutboundTarget() == max_outbound_limit);
 298      const auto time_left_in_cycle{connman.GetMaxOutboundTimeLeftInCycle()};
 299      std::vector<CNodeStats> stats;
 300      connman.GetNodeStats(stats);
 301      const auto bytes_left{connman.GetOutboundTargetBytesLeft()};
 302      assert(bytes_left <= max_outbound_limit);
 303      if (max_outbound_limit == 0) {
 304          assert(bytes_left == 0);
 305          assert(time_left_in_cycle == std::chrono::seconds{0});
 306          assert(!connman.OutboundTargetReached(/*historicalBlockServingLimit=*/false));
 307          assert(!connman.OutboundTargetReached(/*historicalBlockServingLimit=*/true));
 308      }
 309      assert(connman.GetTotalBytesRecv() >= total_bytes_recv_initial);
 310      assert(connman.GetTotalBytesSent() >= total_bytes_sent_initial);
 311      (void)connman.GetTryNewOutboundPeer();
 312      assert(connman.GetUseAddrmanOutgoing() == use_addrman_outgoing);
 313      (void)connman.ASMapHealthCheck();
 314  
 315      connman.ClearTestNodes();
 316      g_dns_lookup = g_dns_lookup_orig;
 317      CreateSock = CreateSockOrig;
 318  }
 319