net_peer_connection_tests.cpp raw

   1  // Copyright (c) 2023-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 <chainparams.h>
   6  #include <compat/compat.h>
   7  #include <net.h>
   8  #include <net_processing.h>
   9  #include <netaddress.h>
  10  #include <netbase.h>
  11  #include <netgroup.h>
  12  #include <node/connection_types.h>
  13  #include <node/protocol_version.h>
  14  #include <protocol.h>
  15  #include <random.h>
  16  #include <test/util/logging.h>
  17  #include <test/util/net.h>
  18  #include <test/util/random.h>
  19  #include <test/util/setup_common.h>
  20  #include <tinyformat.h>
  21  #include <util/chaintype.h>
  22  
  23  #include <algorithm>
  24  #include <cstdint>
  25  #include <memory>
  26  #include <optional>
  27  #include <string>
  28  #include <vector>
  29  
  30  #include <boost/test/unit_test.hpp>
  31  
  32  struct LogIPsTestingSetup : public TestingSetup {
  33      LogIPsTestingSetup()
  34          : TestingSetup{ChainType::MAIN, {.extra_args = {"-logips"}}} {}
  35  };
  36  
  37  BOOST_FIXTURE_TEST_SUITE(net_peer_connection_tests, LogIPsTestingSetup)
  38  
  39  static CService ip(uint32_t i)
  40  {
  41      struct in_addr s;
  42      s.s_addr = i;
  43      return CService{CNetAddr{s}, Params().GetDefaultPort()};
  44  }
  45  
  46  struct PeerTest : LogIPsTestingSetup {
  47  /** Create a peer and connect to it. If the optional `address` (IP/CJDNS only) isn't passed, a random address is created. */
  48  void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, ConnmanTestMsg& connman, ConnectionType conn_type, bool onion_peer = false, std::optional<std::string> address = std::nullopt)
  49  {
  50      CAddress addr{};
  51  
  52      if (address.has_value()) {
  53          addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE};
  54      } else if (onion_peer) {
  55          auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};
  56          BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
  57      }
  58  
  59      while (!addr.IsLocal() && !addr.IsRoutable()) {
  60          addr = CAddress{ip(m_rng.randbits(32)), NODE_NONE};
  61      }
  62  
  63      BOOST_REQUIRE(addr.IsValid());
  64  
  65      const bool inbound_onion{onion_peer && conn_type == ConnectionType::INBOUND};
  66  
  67      nodes.emplace_back(new CNode{++id,
  68                                   /*sock=*/nullptr,
  69                                   addr,
  70                                   /*nKeyedNetGroupIn=*/0,
  71                                   /*nLocalHostNonceIn=*/0,
  72                                   CAddress{},
  73                                   /*addrNameIn=*/"",
  74                                   conn_type,
  75                                   /*inbound_onion=*/inbound_onion,
  76                                   /*network_key=*/0});
  77      CNode& node = *nodes.back();
  78      node.SetCommonVersion(PROTOCOL_VERSION);
  79  
  80      peerman.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
  81      node.fSuccessfullyConnected = true;
  82  
  83      connman.AddTestNode(node);
  84  }
  85  }; // struct PeerTest
  86  
  87  BOOST_FIXTURE_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection, PeerTest)
  88  {
  89      auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
  90      auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
  91      NodeId id{0};
  92      std::vector<CNode*> nodes;
  93  
  94      // Connect a localhost peer.
  95      {
  96          ASSERT_DEBUG_LOG("Added connection to 127.0.0.1:8333 peer=1");
  97          AddPeer(id, nodes, *peerman, *connman, ConnectionType::MANUAL, /*onion_peer=*/false, /*address=*/"127.0.0.1");
  98          BOOST_REQUIRE(nodes.back() != nullptr);
  99      }
 100  
 101      // Call ConnectNode(), which is also called by RPC addnode onetry, for a localhost
 102      // address that resolves to multiple IPs, including that of the connected peer.
 103      // The connection attempt should consistently fail due to the check in ConnectNode().
 104      for (int i = 0; i < 10; ++i) {
 105          ASSERT_DEBUG_LOG("Not opening a connection to localhost, already connected to 127.0.0.1:8333");
 106          BOOST_CHECK(!connman->ConnectNodePublic(*peerman, "localhost", ConnectionType::MANUAL));
 107      }
 108  
 109      // Add 3 more peer connections.
 110      AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
 111      AddPeer(id, nodes, *peerman, *connman, ConnectionType::BLOCK_RELAY, /*onion_peer=*/true);
 112      AddPeer(id, nodes, *peerman, *connman, ConnectionType::INBOUND);
 113  
 114      // Add a CJDNS peer connection.
 115      AddPeer(id, nodes, *peerman, *connman, ConnectionType::INBOUND, /*onion_peer=*/false,
 116              /*address=*/"[fc00:3344:5566:7788:9900:aabb:ccdd:eeff]:1234");
 117      BOOST_CHECK(nodes.back()->IsInboundConn());
 118      BOOST_CHECK_EQUAL(nodes.back()->ConnectedThroughNetwork(), Network::NET_CJDNS);
 119  
 120      BOOST_TEST_MESSAGE("Call AddNode() for all the peers");
 121      for (auto node : connman->TestNodes()) {
 122          BOOST_CHECK(connman->AddNode({/*m_added_node=*/node->addr.ToStringAddrPort(), /*m_use_v2transport=*/true}));
 123          BOOST_TEST_MESSAGE(strprintf("peer id=%s addr=%s", node->GetId(), node->addr.ToStringAddrPort()));
 124      }
 125  
 126      BOOST_TEST_MESSAGE("\nCall AddNode() with 2 addrs resolving to existing localhost addnode entry; neither should be added");
 127      BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.0.0.1", /*m_use_v2transport=*/true}));
 128      // OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes.
 129  #if !defined(__OpenBSD__)
 130      BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.1", /*m_use_v2transport=*/true}));
 131  #endif
 132  
 133      BOOST_TEST_MESSAGE("\nExpect GetAddedNodeInfo to return expected number of peers with `include_connected` true/false");
 134      BOOST_CHECK_EQUAL(connman->GetAddedNodeInfo(/*include_connected=*/true).size(), nodes.size());
 135      BOOST_CHECK(connman->GetAddedNodeInfo(/*include_connected=*/false).empty());
 136  
 137      // Test AddedNodesContain()
 138      for (auto node : connman->TestNodes()) {
 139          BOOST_CHECK(connman->AddedNodesContain(node->addr));
 140      }
 141      AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
 142      BOOST_CHECK(!connman->AddedNodesContain(nodes.back()->addr));
 143  
 144      BOOST_TEST_MESSAGE("\nPrint GetAddedNodeInfo contents:");
 145      for (const auto& info : connman->GetAddedNodeInfo(/*include_connected=*/true)) {
 146          BOOST_TEST_MESSAGE(strprintf("\nadded node: %s", info.m_params.m_added_node));
 147          BOOST_TEST_MESSAGE(strprintf("connected: %s", info.fConnected));
 148          if (info.fConnected) {
 149              BOOST_TEST_MESSAGE(strprintf("IP address: %s", info.resolvedAddress.ToStringAddrPort()));
 150              BOOST_TEST_MESSAGE(strprintf("direction: %s", info.fInbound ? "inbound" : "outbound"));
 151          }
 152      }
 153  
 154      BOOST_TEST_MESSAGE("\nCheck that all connected peers are correctly detected as connected");
 155      for (const auto& node : connman->TestNodes()) {
 156          BOOST_CHECK(connman->AlreadyConnectedToAddressPublic(node->addr));
 157      }
 158  
 159      // Clean up
 160      for (auto node : connman->TestNodes()) {
 161          peerman->FinalizeNode(*node);
 162      }
 163      connman->ClearTestNodes();
 164  }
 165  
 166  BOOST_AUTO_TEST_SUITE_END()
 167