Branch data 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 <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 : 2 : struct LogIPsTestingSetup : public TestingSetup {
33 : 1 : LogIPsTestingSetup()
34 [ + - ]: 2 : : TestingSetup{ChainType::MAIN, {.extra_args = {"-logips"}}} {}
35 : : };
36 : :
37 : : BOOST_FIXTURE_TEST_SUITE(net_peer_connection_tests, LogIPsTestingSetup)
38 : :
39 : 3 : static CService ip(uint32_t i)
40 : : {
41 : 3 : struct in_addr s;
42 : 3 : s.s_addr = i;
43 [ + - + - ]: 6 : return CService{CNetAddr{s}, Params().GetDefaultPort()};
44 : : }
45 : :
46 : 3 : 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 : 0 : 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 : 6 : CAddress addr{};
51 : :
52 [ + + ]: 6 : if (address.has_value()) {
53 [ + - + - : 4 : addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE};
+ - + - +
- ]
54 [ + + ]: 4 : } else if (onion_peer) {
55 : 1 : auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};
56 [ + - - + : 2 : BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
+ - + - +
- ]
57 : 1 : }
58 : :
59 [ + - + + : 9 : while (!addr.IsLocal() && !addr.IsRoutable()) {
+ - + + ]
60 [ + - ]: 6 : addr = CAddress{ip(m_rng.randbits(32)), NODE_NONE};
61 : : }
62 : :
63 [ + - + - : 12 : BOOST_REQUIRE(addr.IsValid());
+ - + - ]
64 : :
65 : 6 : const bool inbound_onion{onion_peer && conn_type == ConnectionType::INBOUND};
66 : :
67 [ + - - - ]: 6 : nodes.emplace_back(new CNode{++id,
68 : : /*sock=*/nullptr,
69 : : addr,
70 : : /*nKeyedNetGroupIn=*/0,
71 : : /*nLocalHostNonceIn=*/0,
72 [ - + ]: 6 : CAddress{},
73 [ + - ]: 12 : /*addrNameIn=*/"",
74 : : conn_type,
75 : : /*inbound_onion=*/inbound_onion,
76 [ + - + - : 18 : /*network_key=*/0});
+ - ]
77 : 6 : CNode& node = *nodes.back();
78 : 6 : node.SetCommonVersion(PROTOCOL_VERSION);
79 : :
80 [ + - ]: 6 : peerman.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
81 [ + - ]: 6 : node.fSuccessfullyConnected = true;
82 : :
83 [ + - ]: 6 : connman.AddTestNode(node);
84 : 6 : }
85 : : }; // struct PeerTest
86 : :
87 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection, PeerTest)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
88 : : {
89 : 1 : auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
90 [ + - ]: 1 : auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
91 : 1 : NodeId id{0};
92 : 1 : std::vector<CNode*> nodes;
93 : :
94 : : // Connect a localhost peer.
95 : 1 : {
96 [ + - + - ]: 2 : ASSERT_DEBUG_LOG("Added connection to 127.0.0.1:8333 peer=1");
97 [ + - + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::MANUAL, /*onion_peer=*/false, /*address=*/"127.0.0.1");
98 [ + - + - ]: 2 : BOOST_REQUIRE(nodes.back() != nullptr);
99 : 0 : }
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 [ + + ]: 11 : for (int i = 0; i < 10; ++i) {
105 [ + - + - ]: 20 : ASSERT_DEBUG_LOG("Not opening a connection to localhost, already connected to 127.0.0.1:8333");
106 [ + - + - : 20 : BOOST_CHECK(!connman->ConnectNodePublic(*peerman, "localhost", ConnectionType::MANUAL));
+ - ]
107 : 10 : }
108 : :
109 : : // Add 3 more peer connections.
110 [ + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
111 [ + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::BLOCK_RELAY, /*onion_peer=*/true);
112 [ + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::INBOUND);
113 : :
114 : : // Add a CJDNS peer connection.
115 [ + - + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::INBOUND, /*onion_peer=*/false,
116 [ + - ]: 1 : /*address=*/"[fc00:3344:5566:7788:9900:aabb:ccdd:eeff]:1234");
117 [ + - + - : 2 : BOOST_CHECK(nodes.back()->IsInboundConn());
+ - ]
118 [ + - + - : 1 : BOOST_CHECK_EQUAL(nodes.back()->ConnectedThroughNetwork(), Network::NET_CJDNS);
+ - ]
119 : :
120 [ + - + - : 1 : BOOST_TEST_MESSAGE("Call AddNode() for all the peers");
+ - ]
121 [ + - + + ]: 6 : for (auto node : connman->TestNodes()) {
122 [ + - + - : 10 : BOOST_CHECK(connman->AddNode({/*m_added_node=*/node->addr.ToStringAddrPort(), /*m_use_v2transport=*/true}));
+ - + - +
- ]
123 [ + - + - : 5 : BOOST_TEST_MESSAGE(strprintf("peer id=%s addr=%s", node->GetId(), node->addr.ToStringAddrPort()));
+ - + - +
- ]
124 : 0 : }
125 : :
126 [ + - + - : 1 : BOOST_TEST_MESSAGE("\nCall AddNode() with 2 addrs resolving to existing localhost addnode entry; neither should be added");
+ - ]
127 [ + - + - : 2 : 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 [ + - + - : 2 : BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.1", /*m_use_v2transport=*/true}));
+ - + - +
- ]
131 : : #endif
132 : :
133 [ + - + - : 1 : BOOST_TEST_MESSAGE("\nExpect GetAddedNodeInfo to return expected number of peers with `include_connected` true/false");
+ - ]
134 [ + - - + : 2 : BOOST_CHECK_EQUAL(connman->GetAddedNodeInfo(/*include_connected=*/true).size(), nodes.size());
+ - + - ]
135 [ + - + - : 2 : BOOST_CHECK(connman->GetAddedNodeInfo(/*include_connected=*/false).empty());
+ - + - ]
136 : :
137 : : // Test AddedNodesContain()
138 [ + - + + ]: 6 : for (auto node : connman->TestNodes()) {
139 [ + - + - : 10 : BOOST_CHECK(connman->AddedNodesContain(node->addr));
+ - ]
140 : 0 : }
141 [ + - ]: 1 : AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
142 [ + - + - : 2 : BOOST_CHECK(!connman->AddedNodesContain(nodes.back()->addr));
+ - + - ]
143 : :
144 [ + - + - : 1 : BOOST_TEST_MESSAGE("\nPrint GetAddedNodeInfo contents:");
+ - ]
145 [ + - + + ]: 6 : for (const auto& info : connman->GetAddedNodeInfo(/*include_connected=*/true)) {
146 [ + - + - : 5 : BOOST_TEST_MESSAGE(strprintf("\nadded node: %s", info.m_params.m_added_node));
+ - + - ]
147 [ + - + - : 5 : BOOST_TEST_MESSAGE(strprintf("connected: %s", info.fConnected));
+ - + - ]
148 [ + - ]: 5 : if (info.fConnected) {
149 [ + - + - : 5 : BOOST_TEST_MESSAGE(strprintf("IP address: %s", info.resolvedAddress.ToStringAddrPort()));
+ - + - +
- ]
150 [ + - + - : 8 : BOOST_TEST_MESSAGE(strprintf("direction: %s", info.fInbound ? "inbound" : "outbound"));
+ + + - +
- ]
151 : : }
152 : 1 : }
153 : :
154 [ + - + - : 1 : BOOST_TEST_MESSAGE("\nCheck that all connected peers are correctly detected as connected");
+ - ]
155 [ + - + + ]: 7 : for (const auto& node : connman->TestNodes()) {
156 [ + - + - : 12 : BOOST_CHECK(connman->AlreadyConnectedToAddressPublic(node->addr));
+ - ]
157 : 0 : }
158 : :
159 : : // Clean up
160 [ + - + + ]: 7 : for (auto node : connman->TestNodes()) {
161 [ + - ]: 6 : peerman->FinalizeNode(*node);
162 : 0 : }
163 [ + - ]: 1 : connman->ClearTestNodes();
164 [ + - + - : 8 : }
+ - ]
165 : :
166 : : BOOST_AUTO_TEST_SUITE_END()
|