From d4dde24034d7467883b290111da60527ab8048f8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 30 Sep 2020 19:07:36 +0300 Subject: [PATCH 1/3] net: Add CNode::m_inbound_onion data member --- src/net.cpp | 10 +++++++--- src/net.h | 13 ++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 95ba6da81..9f8c82774 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -41,6 +41,7 @@ static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"); #endif +#include #include #include @@ -1118,7 +1119,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) { nodeServices = static_cast(nodeServices | NODE_BLOOM); } - CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND); + + const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end(); + CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion); pnode->AddRef(); pnode->m_permissionFlags = permissionFlags; // If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility) @@ -2859,7 +2862,7 @@ int CConnman::GetBestHeight() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in) +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion) : nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), addrBind(addrBindIn), @@ -2871,7 +2874,8 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nLocalHostNonce(nLocalHostNonceIn), m_conn_type(conn_type_in), nLocalServices(nLocalServicesIn), - nMyStartingHeight(nMyStartingHeightIn) + nMyStartingHeight(nMyStartingHeightIn), + m_inbound_onion(inbound_onion) { hSocket = hSocketIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; diff --git a/src/net.h b/src/net.h index 1051511f5..e702c13db 100644 --- a/src/net.h +++ b/src/net.h @@ -253,6 +253,7 @@ public: LOCK(cs_vAddedNodes); vAddedNodes = connOptions.m_added_nodes; } + m_onion_binds = connOptions.onion_binds; } CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true); @@ -586,6 +587,12 @@ private: std::atomic m_next_send_inv_to_incoming{0}; + /** + * A vector of -bind=
:=onion arguments each of which is + * an address and port that are designated for incoming Tor connections. + */ + std::vector m_onion_binds; + friend struct CConnmanTest; friend struct ConnmanTestMsg; }; @@ -1035,7 +1042,7 @@ public: std::set orphan_work_set; - CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn, ConnectionType conn_type_in); + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn, ConnectionType conn_type_in, bool inbound_onion = false); ~CNode(); CNode(const CNode&) = delete; CNode& operator=(const CNode&) = delete; @@ -1073,6 +1080,10 @@ private: // Our address, as reported by the peer CService addrLocal GUARDED_BY(cs_addrLocal); mutable RecursiveMutex cs_addrLocal; + + //! Whether this peer connected via our Tor onion service. + const bool m_inbound_onion{false}; + public: NodeId GetId() const { From 49fba9c1aa699d3aa47ea4dafe07b47c8d0aac6e Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 30 Sep 2020 19:19:19 +0300 Subject: [PATCH 2/3] net: Add CNode::ConnectedThroughNetwork member function --- src/net.cpp | 5 +++++ src/net.h | 12 ++++++++++++ src/netaddress.cpp | 2 +- src/netaddress.h | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 9f8c82774..54d572c68 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -539,6 +539,11 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) { } } +Network CNode::ConnectedThroughNetwork() const +{ + return IsInboundConn() && m_inbound_onion ? NET_ONION : addr.GetNetClass(); +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats, const std::vector &m_asmap) diff --git a/src/net.h b/src/net.h index e702c13db..a8b13124c 100644 --- a/src/net.h +++ b/src/net.h @@ -961,6 +961,18 @@ public: assert(false); } + /** + * Get network the peer connected through. + * + * Returns Network::NET_ONION for *inbound* onion connections, + * and CNetAddr::GetNetClass() otherwise. The latter cannot be used directly + * because it doesn't detect the former, and it's not the responsibility of + * the CNetAddr class to know the actual network a peer is connected through. + * + * @return network the peer connected through. + */ + Network ConnectedThroughNetwork() const; + protected: mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 0c4c0a339..d460d0139 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -629,7 +629,7 @@ uint32_t CNetAddr::GetLinkedIPv4() const assert(false); } -uint32_t CNetAddr::GetNetClass() const +Network CNetAddr::GetNetClass() const { // Make sure that if we return NET_IPV6, then IsIPv6() is true. The callers expect that. diff --git a/src/netaddress.h b/src/netaddress.h index 78e7e1b4b..fe99f41c6 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -182,7 +182,7 @@ class CNetAddr std::string ToStringIP() const; uint64_t GetHash() const; bool GetInAddr(struct in_addr* pipv4Addr) const; - uint32_t GetNetClass() const; + Network GetNetClass() const; //! For IPv4, mapped IPv4, SIIT translated IPv4, Teredo, 6to4 tunneled addresses, return the relevant IPv4 address as a uint32. uint32_t GetLinkedIPv4() const; From 3984b78cd7f49e409377f2175a56e8e4bd71d1d8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 3 Oct 2020 12:18:36 +0300 Subject: [PATCH 3/3] test: Add tests for CNode::ConnectedThroughNetwork --- src/test/fuzz/net.cpp | 4 +++- src/test/net_tests.cpp | 43 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index a85c35324..381883876 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -46,7 +46,8 @@ void test_one_input(const std::vector& buffer) fuzzed_data_provider.ConsumeIntegral(), *address_bind, fuzzed_data_provider.ConsumeRandomLengthString(32), - fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})}; + fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH}), + fuzzed_data_provider.ConsumeBool()}; while (fuzzed_data_provider.ConsumeBool()) { switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { case 0: { @@ -148,4 +149,5 @@ void test_one_input(const std::vector& buffer) fuzzed_data_provider.PickValueInArray({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) : static_cast(fuzzed_data_provider.ConsumeIntegral()); (void)node.HasPermission(net_permission_flags); + (void)node.ConnectedThroughNetwork(); } diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 92792569a..575951d64 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -185,21 +185,60 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); std::string pszDest; - std::unique_ptr pnode1 = MakeUnique(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY); + std::unique_ptr pnode1 = MakeUnique( + id++, NODE_NETWORK, height, hSocket, addr, + /* nKeyedNetGroupIn = */ 0, + /* nLocalHostNonceIn = */ 0, + CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY); BOOST_CHECK(pnode1->IsFullOutboundConn() == true); BOOST_CHECK(pnode1->IsManualConn() == false); BOOST_CHECK(pnode1->IsBlockOnlyConn() == false); BOOST_CHECK(pnode1->IsFeelerConn() == false); BOOST_CHECK(pnode1->IsAddrFetchConn() == false); BOOST_CHECK(pnode1->IsInboundConn() == false); + BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4); - std::unique_ptr pnode2 = MakeUnique(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND); + std::unique_ptr pnode2 = MakeUnique( + id++, NODE_NETWORK, height, hSocket, addr, + /* nKeyedNetGroupIn = */ 1, + /* nLocalHostNonceIn = */ 1, + CAddress(), pszDest, ConnectionType::INBOUND, + /* inbound_onion = */ false); BOOST_CHECK(pnode2->IsFullOutboundConn() == false); BOOST_CHECK(pnode2->IsManualConn() == false); BOOST_CHECK(pnode2->IsBlockOnlyConn() == false); BOOST_CHECK(pnode2->IsFeelerConn() == false); BOOST_CHECK(pnode2->IsAddrFetchConn() == false); BOOST_CHECK(pnode2->IsInboundConn() == true); + BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4); + + std::unique_ptr pnode3 = MakeUnique( + id++, NODE_NETWORK, height, hSocket, addr, + /* nKeyedNetGroupIn = */ 0, + /* nLocalHostNonceIn = */ 0, + CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY, + /* inbound_onion = */ true); + BOOST_CHECK(pnode3->IsFullOutboundConn() == true); + BOOST_CHECK(pnode3->IsManualConn() == false); + BOOST_CHECK(pnode3->IsBlockOnlyConn() == false); + BOOST_CHECK(pnode3->IsFeelerConn() == false); + BOOST_CHECK(pnode3->IsAddrFetchConn() == false); + BOOST_CHECK(pnode3->IsInboundConn() == false); + BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4); + + std::unique_ptr pnode4 = MakeUnique( + id++, NODE_NETWORK, height, hSocket, addr, + /* nKeyedNetGroupIn = */ 1, + /* nLocalHostNonceIn = */ 1, + CAddress(), pszDest, ConnectionType::INBOUND, + /* inbound_onion = */ true); + BOOST_CHECK(pnode4->IsFullOutboundConn() == false); + BOOST_CHECK(pnode4->IsManualConn() == false); + BOOST_CHECK(pnode4->IsBlockOnlyConn() == false); + BOOST_CHECK(pnode4->IsFeelerConn() == false); + BOOST_CHECK(pnode4->IsAddrFetchConn() == false); + BOOST_CHECK(pnode4->IsInboundConn() == true); + BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION); } BOOST_AUTO_TEST_CASE(cnetaddr_basic)