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