/ src / test / net_peer_connection_tests.cpp
net_peer_connection_tests.cpp
  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  /** Create a peer and connect to it. If the optional `address` (IP/CJDNS only) isn't passed, a random address is created. */
 47  static 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)
 48  {
 49      CAddress addr{};
 50  
 51      if (address.has_value()) {
 52          addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE};
 53      } else if (onion_peer) {
 54          auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)};
 55          BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
 56      }
 57  
 58      while (!addr.IsLocal() && !addr.IsRoutable()) {
 59          addr = CAddress{ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE};
 60      }
 61  
 62      BOOST_REQUIRE(addr.IsValid());
 63  
 64      const bool inbound_onion{onion_peer && conn_type == ConnectionType::INBOUND};
 65  
 66      nodes.emplace_back(new CNode{++id,
 67                                   /*sock=*/nullptr,
 68                                   addr,
 69                                   /*nKeyedNetGroupIn=*/0,
 70                                   /*nLocalHostNonceIn=*/0,
 71                                   CAddress{},
 72                                   /*addrNameIn=*/"",
 73                                   conn_type,
 74                                   /*inbound_onion=*/inbound_onion});
 75      CNode& node = *nodes.back();
 76      node.SetCommonVersion(PROTOCOL_VERSION);
 77  
 78      peerman.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
 79      node.fSuccessfullyConnected = true;
 80  
 81      connman.AddTestNode(node);
 82  }
 83  
 84  BOOST_AUTO_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection)
 85  {
 86      auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
 87      auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, {});
 88      NodeId id{0};
 89      std::vector<CNode*> nodes;
 90  
 91      // Connect a localhost peer.
 92      {
 93          ASSERT_DEBUG_LOG("Added connection to 127.0.0.1:8333 peer=1");
 94          AddPeer(id, nodes, *peerman, *connman, ConnectionType::MANUAL, /*onion_peer=*/false, /*address=*/"127.0.0.1");
 95          BOOST_REQUIRE(nodes.back() != nullptr);
 96      }
 97  
 98      // Call ConnectNode(), which is also called by RPC addnode onetry, for a localhost
 99      // address that resolves to multiple IPs, including that of the connected peer.
100      // The connection attempt should consistently fail due to the check in ConnectNode().
101      for (int i = 0; i < 10; ++i) {
102          ASSERT_DEBUG_LOG("Not opening a connection to localhost, already connected to 127.0.0.1:8333");
103          BOOST_CHECK(!connman->ConnectNodePublic(*peerman, "localhost", ConnectionType::MANUAL));
104      }
105  
106      // Add 3 more peer connections.
107      AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
108      AddPeer(id, nodes, *peerman, *connman, ConnectionType::BLOCK_RELAY, /*onion_peer=*/true);
109      AddPeer(id, nodes, *peerman, *connman, ConnectionType::INBOUND);
110  
111      BOOST_TEST_MESSAGE("Call AddNode() for all the peers");
112      for (auto node : connman->TestNodes()) {
113          BOOST_CHECK(connman->AddNode({/*m_added_node=*/node->addr.ToStringAddrPort(), /*m_use_v2transport=*/true}));
114          BOOST_TEST_MESSAGE(strprintf("peer id=%s addr=%s", node->GetId(), node->addr.ToStringAddrPort()));
115      }
116  
117      BOOST_TEST_MESSAGE("\nCall AddNode() with 2 addrs resolving to existing localhost addnode entry; neither should be added");
118      BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.0.0.1", /*m_use_v2transport=*/true}));
119      // OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes.
120  #if !defined(__OpenBSD__)
121      BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.1", /*m_use_v2transport=*/true}));
122  #endif
123  
124      BOOST_TEST_MESSAGE("\nExpect GetAddedNodeInfo to return expected number of peers with `include_connected` true/false");
125      BOOST_CHECK_EQUAL(connman->GetAddedNodeInfo(/*include_connected=*/true).size(), nodes.size());
126      BOOST_CHECK(connman->GetAddedNodeInfo(/*include_connected=*/false).empty());
127  
128      // Test AddedNodesContain()
129      for (auto node : connman->TestNodes()) {
130          BOOST_CHECK(connman->AddedNodesContain(node->addr));
131      }
132      AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
133      BOOST_CHECK(!connman->AddedNodesContain(nodes.back()->addr));
134  
135      BOOST_TEST_MESSAGE("\nPrint GetAddedNodeInfo contents:");
136      for (const auto& info : connman->GetAddedNodeInfo(/*include_connected=*/true)) {
137          BOOST_TEST_MESSAGE(strprintf("\nadded node: %s", info.m_params.m_added_node));
138          BOOST_TEST_MESSAGE(strprintf("connected: %s", info.fConnected));
139          if (info.fConnected) {
140              BOOST_TEST_MESSAGE(strprintf("IP address: %s", info.resolvedAddress.ToStringAddrPort()));
141              BOOST_TEST_MESSAGE(strprintf("direction: %s", info.fInbound ? "inbound" : "outbound"));
142          }
143      }
144  
145      BOOST_TEST_MESSAGE("\nCheck that all connected peers are correctly detected as connected");
146      for (auto node : connman->TestNodes()) {
147          BOOST_CHECK(connman->AlreadyConnectedPublic(node->addr));
148      }
149  
150      // Clean up
151      for (auto node : connman->TestNodes()) {
152          peerman->FinalizeNode(*node);
153      }
154      connman->ClearTestNodes();
155  }
156  
157  BOOST_AUTO_TEST_SUITE_END()