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()