aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net.cpp29
-rw-r--r--src/net.h16
-rw-r--r--src/net_processing.cpp11
-rw-r--r--src/node/connection_types.cpp14
-rw-r--r--src/node/connection_types.h11
-rw-r--r--src/rpc/net.cpp10
-rw-r--r--src/test/fuzz/p2p_transport_serialization.cpp3
-rw-r--r--src/test/net_tests.cpp12
-rwxr-xr-xtest/functional/rpc_net.py2
9 files changed, 104 insertions, 4 deletions
diff --git a/src/net.cpp b/src/net.cpp
index a3f1a18fe7..a3792b7d49 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -667,6 +667,9 @@ void CNode::CopyStats(CNodeStats& stats)
LOCK(cs_vRecv);
X(mapRecvBytesPerMsgType);
X(nRecvBytes);
+ Transport::Info info = m_transport->GetInfo();
+ stats.m_transport_type = info.transport_type;
+ if (info.session_id) stats.m_session_id = HexStr(*info.session_id);
}
X(m_permission_flags);
@@ -734,6 +737,11 @@ V1Transport::V1Transport(const NodeId node_id, int nTypeIn, int nVersionIn) noex
Reset();
}
+Transport::Info V1Transport::GetInfo() const noexcept
+{
+ return {.transport_type = TransportProtocolType::V1, .session_id = {}};
+}
+
int V1Transport::readHeader(Span<const uint8_t> msg_bytes)
{
AssertLockHeld(m_recv_mutex);
@@ -1582,6 +1590,27 @@ size_t V2Transport::GetSendMemoryUsage() const noexcept
return sizeof(m_send_buffer) + memusage::DynamicUsage(m_send_buffer);
}
+Transport::Info V2Transport::GetInfo() const noexcept
+{
+ AssertLockNotHeld(m_recv_mutex);
+ LOCK(m_recv_mutex);
+ if (m_recv_state == RecvState::V1) return m_v1_fallback.GetInfo();
+
+ Transport::Info info;
+
+ // Do not report v2 and session ID until the version packet has been received
+ // and verified (confirming that the other side very likely has the same keys as us).
+ if (m_recv_state != RecvState::KEY_MAYBE_V1 && m_recv_state != RecvState::KEY &&
+ m_recv_state != RecvState::GARB_GARBTERM && m_recv_state != RecvState::VERSION) {
+ info.transport_type = TransportProtocolType::V2;
+ info.session_id = uint256(MakeUCharSpan(m_cipher.GetSessionID()));
+ } else {
+ info.transport_type = TransportProtocolType::DETECTING;
+ }
+
+ return info;
+}
+
std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const
{
auto it = node.vSendMsg.begin();
diff --git a/src/net.h b/src/net.h
index 297e408320..2f7b832fba 100644
--- a/src/net.h
+++ b/src/net.h
@@ -232,6 +232,10 @@ public:
Network m_network;
uint32_t m_mapped_as;
ConnectionType m_conn_type;
+ /** Transport protocol type. */
+ TransportProtocolType m_transport_type;
+ /** BIP324 session id string in hex, if any. */
+ std::string m_session_id;
};
@@ -268,6 +272,15 @@ class Transport {
public:
virtual ~Transport() {}
+ struct Info
+ {
+ TransportProtocolType transport_type;
+ std::optional<uint256> session_id;
+ };
+
+ /** Retrieve information about this transport. */
+ virtual Info GetInfo() const noexcept = 0;
+
// 1. Receiver side functions, for decoding bytes received on the wire into transport protocol
// agnostic CNetMessage (message type & payload) objects.
@@ -426,6 +439,8 @@ public:
return WITH_LOCK(m_recv_mutex, return CompleteInternal());
}
+ Info GetInfo() const noexcept override;
+
bool ReceivedBytes(Span<const uint8_t>& msg_bytes) override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex)
{
AssertLockNotHeld(m_recv_mutex);
@@ -664,6 +679,7 @@ public:
// Miscellaneous functions.
bool ShouldReconnectV1() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex, !m_send_mutex);
+ Info GetInfo() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex);
};
struct CNodeOptions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 03dee13512..06086d6804 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3585,13 +3585,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- if (!pfrom.IsInboundConn()) {
+ // Log succesful connections unconditionally for outbound, but not for inbound as those
+ // can be triggered by an attacker at high rate.
+ if (!pfrom.IsInboundConn() || LogAcceptCategory(BCLog::NET, BCLog::Level::Debug)) {
const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
- LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s%s (%s)\n",
+ LogPrintf("New %s %s peer connected: version: %d, blocks=%d, peer=%d%s%s\n",
+ pfrom.ConnectionTypeAsString(),
+ TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),
pfrom.nVersion.load(), peer->m_starting_height,
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""),
- (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""),
- pfrom.ConnectionTypeAsString());
+ (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
}
if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) {
diff --git a/src/node/connection_types.cpp b/src/node/connection_types.cpp
index 904f4371aa..5e4dc5bf2e 100644
--- a/src/node/connection_types.cpp
+++ b/src/node/connection_types.cpp
@@ -24,3 +24,17 @@ std::string ConnectionTypeAsString(ConnectionType conn_type)
assert(false);
}
+
+std::string TransportTypeAsString(TransportProtocolType transport_type)
+{
+ switch (transport_type) {
+ case TransportProtocolType::DETECTING:
+ return "detecting";
+ case TransportProtocolType::V1:
+ return "v1";
+ case TransportProtocolType::V2:
+ return "v2";
+ } // no default case, so the compiler can warn about missing cases
+
+ assert(false);
+}
diff --git a/src/node/connection_types.h b/src/node/connection_types.h
index 5e1abcace6..a911b95f7e 100644
--- a/src/node/connection_types.h
+++ b/src/node/connection_types.h
@@ -6,6 +6,7 @@
#define BITCOIN_NODE_CONNECTION_TYPES_H
#include <string>
+#include <stdint.h>
/** Different types of connections to a peer. This enum encapsulates the
* information we have available at the time of opening or accepting the
@@ -79,4 +80,14 @@ enum class ConnectionType {
/** Convert ConnectionType enum to a string value */
std::string ConnectionTypeAsString(ConnectionType conn_type);
+/** Transport layer version */
+enum class TransportProtocolType : uint8_t {
+ DETECTING, //!< Peer could be v1 or v2
+ V1, //!< Unencrypted, plaintext protocol
+ V2, //!< BIP324 protocol
+};
+
+/** Convert TransportProtocolType enum to a string value */
+std::string TransportTypeAsString(TransportProtocolType transport_type);
+
#endif // BITCOIN_NODE_CONNECTION_TYPES_H
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 3be91f292c..8d796b8e9b 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -45,6 +45,12 @@ const std::vector<std::string> CONNECTION_TYPE_DOC{
"feeler (short-lived automatic connection for testing addresses)"
};
+const std::vector<std::string> TRANSPORT_TYPE_DOC{
+ "detecting (peer could be v1 or v2)",
+ "v1 (plaintext transport protocol)",
+ "v2 (BIP324 encrypted transport protocol)"
+};
+
static RPCHelpMan getconnectioncount()
{
return RPCHelpMan{"getconnectioncount",
@@ -164,6 +170,8 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
"Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
"best capture connection behaviors."},
+ {RPCResult::Type::STR, "transport_protocol_type", "Type of transport protocol: \n" + Join(TRANSPORT_TYPE_DOC, ",\n") + ".\n"},
+ {RPCResult::Type::STR, "session_id", "The session ID for this connection, or \"\" if there is none (\"v2\" transport protocol only).\n"},
}},
}},
},
@@ -268,6 +276,8 @@ static RPCHelpMan getpeerinfo()
}
obj.pushKV("bytesrecv_per_msg", recvPerMsgType);
obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));
+ obj.pushKV("transport_protocol_type", TransportTypeAsString(stats.m_transport_type));
+ obj.pushKV("session_id", stats.m_session_id);
ret.push_back(obj);
}
diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp
index 88d6e96eac..21d8dab536 100644
--- a/src/test/fuzz/p2p_transport_serialization.cpp
+++ b/src/test/fuzz/p2p_transport_serialization.cpp
@@ -328,6 +328,9 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa
// Make sure all expected messages were received.
assert(expected[0].empty());
assert(expected[1].empty());
+
+ // Compare session IDs.
+ assert(transports[0]->GetInfo().session_id == transports[1]->GetInfo().session_id);
}
std::unique_ptr<Transport> MakeV1Transport(NodeId nodeid) noexcept
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 1df08127ad..5976aa3713 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1321,6 +1321,14 @@ public:
SendPacket(contents);
}
+ /** Test whether the transport's session ID matches the session ID we expect. */
+ void CompareSessionIDs() const
+ {
+ auto info = m_transport.GetInfo();
+ BOOST_CHECK(info.session_id);
+ BOOST_CHECK(uint256(MakeUCharSpan(m_cipher.GetSessionID())) == *info.session_id);
+ }
+
/** Introduce a bit error in the data scheduled to be sent. */
void Damage()
{
@@ -1346,6 +1354,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
BOOST_REQUIRE(ret && ret->empty());
tester.ReceiveGarbage();
tester.ReceiveVersion();
+ tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000));
auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
tester.SendMessage(uint8_t(4), msg_data_1); // cmpctblock short id
@@ -1386,6 +1395,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
BOOST_REQUIRE(ret && ret->empty());
tester.ReceiveGarbage();
tester.ReceiveVersion();
+ tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000));
auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
tester.SendMessage(uint8_t(14), msg_data_1); // inv short id
@@ -1439,6 +1449,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
BOOST_REQUIRE(ret && ret->empty());
tester.ReceiveGarbage();
tester.ReceiveVersion();
+ tester.CompareSessionIDs();
for (unsigned d = 0; d < num_decoys_1; ++d) {
auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000));
tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true);
@@ -1516,6 +1527,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
BOOST_REQUIRE(ret && ret->empty());
tester.ReceiveGarbage();
tester.ReceiveVersion();
+ tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that receiving 4M payload works
auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that sending 4M payload works
tester.SendMessage(uint8_t(InsecureRandRange(223) + 33), {}); // unknown short id
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 117802b812..a87944a062 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -142,11 +142,13 @@ class NetTest(BitcoinTestFramework):
"relaytxes": False,
"services": "0000000000000000",
"servicesnames": [],
+ "session_id": "",
"startingheight": -1,
"subver": "",
"synced_blocks": -1,
"synced_headers": -1,
"timeoffset": 0,
+ "transport_protocol_type": "v1",
"version": 0,
},
)