v29.4-roots.2 · Commit 3: [PATCH 03/21] policy: restore conservative relay and network controls
src/net.cpp
Before: src/net.cpp · After: src/net.cpp
File metadata
index 7684877ec352cfbee891ee61501367d1169e88d5..05ee7224226c339bbe7ad04c8fdf1a4dedc199bd 100644
Download original patch · Release notes
Diff rows 1–397 of 397. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/net.cpp
CHANGED
|
@@ -115,7 +115,7 @@ const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
|
|
|
115
115
|
|
|
116
116
|
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
|
|
117
117
|
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
|
|
118
|
-
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
|
|
118
|
+
static const uint64_t RANDOMIZER_ID_NETWORKKEY = 0x0e8a2b136c592a7dULL; // SHA256("networkkey")[0:8]
|
|
119
119
|
//
|
|
120
120
|
// Global state variables
|
|
121
121
|
//
|
|
@@ -228,7 +228,7 @@ CService GetLocalAddress(const CNode& peer)
|
|
|
228
228
|
return GetLocal(peer).value_or(CService{CNetAddr(), GetListenPort()});
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
static int GetnScore(const CService& addr)
|
|
231
|
+
int GetnScore(const CService& addr)
|
|
232
232
|
{
|
|
233
233
|
LOCK(g_maplocalhost_mutex);
|
|
234
234
|
const auto it = mapLocalHost.find(addr);
|
|
@@ -284,7 +284,8 @@ bool AddLocal(const CService& addr_, int nScore)
|
|
|
284
284
|
if (!fDiscover && nScore < LOCAL_MANUAL)
|
|
285
285
|
return false;
|
|
286
286
|
|
|
287
|
-
if (!g_reachable_nets.Contains(addr))
|
|
287
|
+
// IPv4 and IPv6 cannot be connected to unless their networks are reachable, but Tor is not necessarily bidirectional
|
|
288
|
+
if (!(g_reachable_nets.Contains(addr) || addr.IsTor()))
|
|
288
289
|
return false;
|
|
289
290
|
|
|
290
291
|
LogPrintf("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore);
|
|
@@ -309,9 +310,11 @@ bool AddLocal(const CNetAddr &addr, int nScore)
|
|
|
309
310
|
|
|
310
311
|
void RemoveLocal(const CService& addr)
|
|
311
312
|
{
|
|
312
|
-
LOCK(g_maplocalhost_mutex);
|
|
313
|
-
LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort());
|
|
314
|
-
mapLocalHost.erase(addr);
|
|
313
|
+
{
|
|
314
|
+
LOCK(g_maplocalhost_mutex);
|
|
315
|
+
LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort());
|
|
316
|
+
mapLocalHost.erase(addr);
|
|
317
|
+
}
|
|
315
318
|
}
|
|
316
319
|
|
|
317
320
|
/** vote for a local address */
|
|
@@ -320,7 +323,9 @@ bool SeenLocal(const CService& addr)
|
|
|
320
323
|
LOCK(g_maplocalhost_mutex);
|
|
321
324
|
const auto it = mapLocalHost.find(addr);
|
|
322
325
|
if (it == mapLocalHost.end()) return false;
|
|
323
|
-
++it->second.nScore;
|
|
326
|
+
if (it->second.nScore < std::numeric_limits<int>::max()) {
|
|
327
|
+
++it->second.nScore;
|
|
328
|
+
}
|
|
324
329
|
return true;
|
|
325
330
|
}
|
|
326
331
|
|
|
@@ -463,6 +468,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|
|
463
468
|
std::unique_ptr<i2p::sam::Session> i2p_transient_session;
|
|
464
469
|
|
|
465
470
|
for (auto& target_addr: connect_to) {
|
|
471
|
+
if (DisableV1OnClearnet(target_addr.GetNetClass()) && !use_v2transport) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
466
474
|
if (target_addr.IsValid()) {
|
|
467
475
|
const bool use_proxy{GetProxy(target_addr.GetNetwork(), proxy)};
|
|
468
476
|
bool proxyConnectionFailed = false;
|
|
@@ -522,8 +530,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|
|
522
530
|
}
|
|
523
531
|
|
|
524
532
|
NetPermissionFlags permission_flags = NetPermissionFlags::None;
|
|
525
|
-
std::vector<NetWhitelistPermissions> whitelist_permissions = conn_type == ConnectionType::MANUAL ? vWhitelistedRangeOutgoing : std::vector<NetWhitelistPermissions>{};
|
|
526
|
-
AddWhitelistPermissionFlags(permission_flags, target_addr, whitelist_permissions);
|
|
533
|
+
AddWhitelistPermissionFlags(permission_flags, target_addr, vWhitelistedRangeOutgoing);
|
|
527
534
|
|
|
528
535
|
// Add node
|
|
529
536
|
NodeId id = GetNewNodeId();
|
|
@@ -531,6 +538,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|
|
531
538
|
if (!addr_bind.IsValid()) {
|
|
532
539
|
addr_bind = GetBindAddress(*sock);
|
|
533
540
|
}
|
|
541
|
+
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
|
542
|
+
.Write(target_addr.GetNetClass())
|
|
543
|
+
.Write(addr_bind.GetAddrBytes())
|
|
544
|
+
// For outbound connections, the port of the bound address is randomly
|
|
545
|
+
// assigned by the OS and would therefore not be useful for seeding.
|
|
546
|
+
.Write(0)
|
|
547
|
+
.Finalize();
|
|
534
548
|
CNode* pnode = new CNode(id,
|
|
535
549
|
std::move(sock),
|
|
536
550
|
target_addr,
|
|
@@ -540,6 +554,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
|
|
540
554
|
pszDest ? pszDest : "",
|
|
541
555
|
conn_type,
|
|
542
556
|
/*inbound_onion=*/false,
|
|
557
|
+
network_id,
|
|
543
558
|
CNodeOptions{
|
|
544
559
|
.permission_flags = permission_flags,
|
|
545
560
|
.i2p_sam_session = std::move(i2p_transient_session),
|
|
@@ -587,6 +602,7 @@ void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optio
|
|
|
587
602
|
if (whitelist_relay) NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
|
|
588
603
|
NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
|
|
589
604
|
NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
|
|
605
|
+
NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
|
|
590
606
|
}
|
|
591
607
|
}
|
|
592
608
|
|
|
@@ -651,6 +667,7 @@ void CNode::CopyStats(CNodeStats& stats)
|
|
|
651
667
|
if (info.session_id) stats.m_session_id = HexStr(*info.session_id);
|
|
652
668
|
}
|
|
653
669
|
X(m_permission_flags);
|
|
670
|
+
X(m_forced_inbound);
|
|
654
671
|
|
|
655
672
|
X(m_last_ping_time);
|
|
656
673
|
X(m_min_ping_time);
|
|
@@ -660,6 +677,8 @@ void CNode::CopyStats(CNodeStats& stats)
|
|
|
660
677
|
stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToStringAddrPort() : "";
|
|
661
678
|
|
|
662
679
|
X(m_conn_type);
|
|
680
|
+
|
|
681
|
+
X(m_cpu_time);
|
|
663
682
|
}
|
|
664
683
|
#undef X
|
|
665
684
|
|
|
@@ -1683,7 +1702,7 @@ std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const
|
|
|
1683
1702
|
* to forge. In order to partition a node the attacker must be
|
|
1684
1703
|
* simultaneously better at all of them than honest peers.
|
|
1685
1704
|
*/
|
|
1686
|
-
bool CConnman::AttemptToEvictConnection()
|
|
1705
|
+
bool CConnman::AttemptToEvictConnection(bool force)
|
|
1687
1706
|
{
|
|
1688
1707
|
std::vector<NodeEvictionCandidate> vEvictionCandidates;
|
|
1689
1708
|
{
|
|
@@ -1711,7 +1730,7 @@ bool CConnman::AttemptToEvictConnection()
|
|
|
1711
1730
|
vEvictionCandidates.push_back(candidate);
|
|
1712
1731
|
}
|
|
1713
1732
|
}
|
|
1714
|
-
const std::optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates));
|
|
1733
|
+
const std::optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates), force);
|
|
1715
1734
|
if (!node_id_to_evict) {
|
|
1716
1735
|
return false;
|
|
1717
1736
|
}
|
|
@@ -1767,7 +1786,26 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|
|
1767
1786
|
{
|
|
1768
1787
|
int nInbound = 0;
|
|
1769
1788
|
|
|
1770
|
-
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
|
|
1789
|
+
const bool inbound_onion = [this, &addr, &addr_bind]{
|
|
1790
|
+
if (m_onion_binds.empty()) {
|
|
1791
|
+
if (!m_listenonion) {
|
|
1792
|
+
// If -listenonion=0, assume we do not have inbound Tor connections on non-onion listeners
|
|
1793
|
+
return false;
|
|
1794
|
+
}
|
|
1795
|
+
// Tor connections are coming in on the first -bind
|
|
1796
|
+
if ((!m_normal_binds.empty()) && addr_bind == m_normal_binds.front()) {
|
|
1797
|
+
if (addr_bind.IsBindAny()) {
|
|
1798
|
+
// Tor connections should have a source IP that is local
|
|
1799
|
+
return addr.IsLocal();
|
|
1800
|
+
}
|
|
1801
|
+
// Otherwise, the source IP is unpredictable, so assume anything could be onion
|
|
1802
|
+
return true;
|
|
1803
|
+
}
|
|
1804
|
+
return false;
|
|
1805
|
+
} else {
|
|
1806
|
+
return std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
|
|
1807
|
+
}
|
|
1808
|
+
}();
|
|
1771
1809
|
|
|
1772
1810
|
// Tor inbound connections do not reveal the peer's actual network address.
|
|
1773
1811
|
// Therefore do not apply address-based whitelist permissions to them.
|
|
@@ -1814,13 +1852,19 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|
|
1814
1852
|
return;
|
|
1815
1853
|
}
|
|
1816
1854
|
|
|
1855
|
+
bool forced{false};
|
|
1817
1856
|
if (nInbound >= m_max_inbound)
|
|
1818
1857
|
{
|
|
1819
|
-
if (!AttemptToEvictConnection()) {
|
|
1858
|
+
// If the inbound connection attempt is granted ForceInbound permission, try a little harder
|
|
1859
|
+
// to make room by evicting a peer we may not have otherwise evicted.
|
|
1860
|
+
if (!AttemptToEvictConnection(NetPermissions::HasFlag(permission_flags, NetPermissionFlags::ForceInbound))) {
|
|
1820
1861
|
// No connection to evict, disconnect the new connection
|
|
1821
1862
|
LogDebug(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n");
|
|
1822
1863
|
return;
|
|
1823
1864
|
}
|
|
1865
|
+
|
|
1866
|
+
// We kicked someone out
|
|
1867
|
+
forced = true;
|
|
1824
1868
|
}
|
|
1825
1869
|
|
|
1826
1870
|
NodeId id = GetNewNodeId();
|
|
@@ -1831,6 +1875,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|
|
1831
1875
|
ServiceFlags local_services = GetLocalServices();
|
|
1832
1876
|
const bool use_v2transport(local_services & NODE_P2P_V2);
|
|
1833
1877
|
|
|
1878
|
+
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
|
|
1879
|
+
.Write(inbound_onion ? NET_ONION : addr.GetNetClass())
|
|
1880
|
+
.Write(addr_bind.GetAddrBytes())
|
|
1881
|
+
.Write(addr_bind.GetPort()) // inbound connections use bind port
|
|
1882
|
+
.Finalize();
|
|
1834
1883
|
CNode* pnode = new CNode(id,
|
|
1835
1884
|
std::move(sock),
|
|
1836
1885
|
CAddress{addr, NODE_NONE},
|
|
@@ -1840,9 +1889,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|
|
1840
1889
|
/*addrNameIn=*/"",
|
|
1841
1890
|
ConnectionType::INBOUND,
|
|
1842
1891
|
inbound_onion,
|
|
1892
|
+
network_id,
|
|
1843
1893
|
CNodeOptions{
|
|
1844
1894
|
.permission_flags = permission_flags,
|
|
1845
1895
|
.prefer_evict = discouraged,
|
|
1896
|
+
.forced_inbound = forced,
|
|
1846
1897
|
.recv_flood_size = nReceiveFloodSize,
|
|
1847
1898
|
.use_v2transport = use_v2transport,
|
|
1848
1899
|
});
|
|
@@ -1913,7 +1964,8 @@ void CConnman::DisconnectNodes()
|
|
|
1913
1964
|
{
|
|
1914
1965
|
LOCK(m_nodes_mutex);
|
|
1915
1966
|
|
|
1916
|
-
if (!fNetworkActive) {
|
|
1967
|
+
const bool network_active{fNetworkActive};
|
|
1968
|
+
if (!network_active) {
|
|
1917
1969
|
// Disconnect any connected nodes
|
|
1918
1970
|
for (CNode* pnode : m_nodes) {
|
|
1919
1971
|
if (!pnode->fDisconnect) {
|
|
@@ -1935,7 +1987,7 @@ void CConnman::DisconnectNodes()
|
|
|
1935
1987
|
// Add to reconnection list if appropriate. We don't reconnect right here, because
|
|
1936
1988
|
// the creation of a connection is a blocking operation (up to several seconds),
|
|
1937
1989
|
// and we don't want to hold up the socket handler thread for that long.
|
|
1938
|
-
if (pnode->m_transport->ShouldReconnectV1()) {
|
|
1990
|
+
if (network_active && pnode->m_transport->ShouldReconnectV1() && !DisableV1OnClearnet(pnode->addr.GetNetClass())) {
|
|
1939
1991
|
reconnections_to_add.push_back({
|
|
1940
1992
|
.addr_connect = pnode->addr,
|
|
1941
1993
|
.grant = std::move(pnode->grantOutbound),
|
|
@@ -1994,16 +2046,15 @@ void CConnman::NotifyNumConnectionsChanged()
|
|
|
1994
2046
|
}
|
|
1995
2047
|
}
|
|
1996
2048
|
|
|
1997
|
-
bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const
|
|
2049
|
+
bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::chrono::microseconds now) const
|
|
1998
2050
|
{
|
|
1999
2051
|
return node.m_connected + m_peer_connect_timeout < now;
|
|
2000
2052
|
}
|
|
2001
2053
|
|
|
2002
|
-
bool CConnman::InactivityCheck(const CNode& node) const
|
|
2054
|
+
bool CConnman::InactivityCheck(const CNode& node, std::chrono::microseconds now) const
|
|
2003
2055
|
{
|
|
2004
2056
|
// Tests that see disconnects after using mocktime can start nodes with a
|
|
2005
2057
|
// large timeout. For example, -peertimeout=999999999.
|
|
2006
|
-
const auto now{GetTime<std::chrono::seconds>()};
|
|
2007
2058
|
const auto last_send{node.m_last_send.load()};
|
|
2008
2059
|
const auto last_recv{node.m_last_recv.load()};
|
|
2009
2060
|
|
|
@@ -2027,7 +2078,7 @@ bool CConnman::InactivityCheck(const CNode& node) const
|
|
|
2027
2078
|
|
|
2028
2079
|
if (now > last_send + TIMEOUT_INTERVAL) {
|
|
2029
2080
|
LogDebug(BCLog::NET,
|
|
2030
|
-
"socket sending timeout: %is, %s\n", count_seconds(now - last_send),
|
|
2081
|
+
"socket sending timeout: %is, %s\n", Ticks<std::chrono::seconds>(now - last_send),
|
|
2031
2082
|
node.DisconnectMsg(fLogIPs)
|
|
2032
2083
|
);
|
|
2033
2084
|
return true;
|
|
@@ -2035,7 +2086,7 @@ bool CConnman::InactivityCheck(const CNode& node) const
|
|
|
2035
2086
|
|
|
2036
2087
|
if (now > last_recv + TIMEOUT_INTERVAL) {
|
|
2037
2088
|
LogDebug(BCLog::NET,
|
|
2038
|
-
"socket receive timeout: %is, %s\n", count_seconds(now - last_recv),
|
|
2089
|
+
"socket receive timeout: %is, %s\n", Ticks<std::chrono::seconds>(now - last_recv),
|
|
2039
2090
|
node.DisconnectMsg(fLogIPs)
|
|
2040
2091
|
);
|
|
2041
2092
|
return true;
|
|
@@ -2117,6 +2168,8 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
|
|
|
2117
2168
|
{
|
|
2118
2169
|
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
|
2119
2170
|
|
|
2171
|
+
auto now = GetTime<std::chrono::microseconds>();
|
|
2172
|
+
|
|
2120
2173
|
for (CNode* pnode : nodes) {
|
|
2121
2174
|
if (interruptNet)
|
|
2122
2175
|
return;
|
|
@@ -2207,7 +2260,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
|
|
|
2207
2260
|
}
|
|
2208
2261
|
}
|
|
2209
2262
|
|
|
2210
|
-
if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
|
|
2263
|
+
if (InactivityCheck(*pnode, now)) pnode->fDisconnect = true;
|
|
2211
2264
|
}
|
|
2212
2265
|
}
|
|
2213
2266
|
|
|
@@ -2498,6 +2551,11 @@ bool CConnman::MultipleManualOrFullOutboundConns(Network net) const
|
|
|
2498
2551
|
return m_network_conn_counts[net] > 1;
|
|
2499
2552
|
}
|
|
2500
2553
|
|
|
2554
|
+
bool CConnman::DisableV1OnClearnet(Network net) const
|
|
2555
|
+
{
|
|
2556
|
+
return disable_v1conn_clearnet && (net == NET_IPV4 || net == NET_IPV6);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2501
2559
|
bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network)
|
|
2502
2560
|
{
|
|
2503
2561
|
std::array<Network, 5> nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS};
|
|
@@ -3050,6 +3108,8 @@ void CConnman::ThreadMessageHandler()
|
|
|
3050
3108
|
if (pnode->fDisconnect)
|
|
3051
3109
|
continue;
|
|
3052
3110
|
|
|
3111
|
+
CpuTimer timer{[&pnode](std::chrono::nanoseconds elapsed) { pnode->m_cpu_time += elapsed; }};
|
|
3112
|
+
|
|
3053
3113
|
// Receive messages
|
|
3054
3114
|
bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
|
|
3055
3115
|
fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
|
|
@@ -3287,7 +3347,29 @@ bool CConnman::InitBinds(const Options& options)
|
|
|
3287
3347
|
inaddr_any.s_addr = htonl(INADDR_ANY);
|
|
3288
3348
|
const CService ipv4_any{inaddr_any, GetListenPort()}; // 0.0.0.0
|
|
3289
3349
|
if (!Bind(ipv4_any, BF_REPORT_ERROR, NetPermissionFlags::None)) {
|
|
3290
|
-
return false;
|
|
3350
|
+
int defaultPort = Params().GetDefaultPort();
|
|
3351
|
+
// If listening failed and another port than the standard port was specified,
|
|
3352
|
+
// ask if the user wants to connect via the standard port for the network instead
|
|
3353
|
+
if (GetListenPort() != defaultPort) {
|
|
3354
|
+
bool fRet = uiInterface.ThreadSafeQuestion(
|
|
3355
|
+
strprintf(_("Do you want to use the standard network port for %s (port %s) instead?"), CLIENT_NAME, defaultPort),
|
|
3356
|
+
strprintf(_("Listen on port %s failed."), GetListenPort()).translated,
|
|
3357
|
+
"", CClientUIInterface::MSG_INFORMATION | CClientUIInterface::MODAL | CClientUIInterface::BTN_OK | CClientUIInterface::BTN_ABORT);
|
|
3358
|
+
|
|
3359
|
+
if (fRet) {
|
|
3360
|
+
// FIXME: Unbind IPv6 on the other port
|
|
3361
|
+
|
|
3362
|
+
gArgs.ForceSetArg("-port", defaultPort);
|
|
3363
|
+
// Attempt to use standard port
|
|
3364
|
+
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
|
|
3365
|
+
Bind(CService(inaddr6_any, defaultPort), BF_NONE, NetPermissionFlags::None);
|
|
3366
|
+
struct in_addr inaddr_any;
|
|
3367
|
+
inaddr_any.s_addr = INADDR_ANY;
|
|
3368
|
+
if (!Bind(CService(inaddr_any, defaultPort), BF_REPORT_ERROR, NetPermissionFlags::None)) {
|
|
3369
|
+
return false;
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3291
3373
|
}
|
|
3292
3374
|
}
|
|
3293
3375
|
return true;
|
|
@@ -3458,6 +3540,8 @@ void CConnman::StopThreads()
|
|
|
3458
3540
|
|
|
3459
3541
|
void CConnman::StopNodes()
|
|
3460
3542
|
{
|
|
3543
|
+
AssertLockNotHeld(m_reconnections_mutex);
|
|
3544
|
+
|
|
3461
3545
|
if (fAddressesInitialized) {
|
|
3462
3546
|
DumpAddresses();
|
|
3463
3547
|
fAddressesInitialized = false;
|
|
@@ -3485,6 +3569,7 @@ void CConnman::StopNodes()
|
|
|
3485
3569
|
DeleteNode(pnode);
|
|
3486
3570
|
}
|
|
3487
3571
|
m_nodes_disconnected.clear();
|
|
3572
|
+
WITH_LOCK(m_reconnections_mutex, m_reconnections.clear());
|
|
3488
3573
|
vhListenSocket.clear();
|
|
3489
3574
|
semOutbound.reset();
|
|
3490
3575
|
semAddnode.reset();
|
|
@@ -3517,15 +3602,9 @@ std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pc
|
|
|
3517
3602
|
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
|
|
3518
3603
|
{
|
|
3519
3604
|
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
|
|
3520
|
-
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
|
|
3521
|
-
.Write(requestor.ConnectedThroughNetwork())
|
|
3522
|
-
.Write(local_socket_bytes)
|
|
3523
|
-
// For outbound connections, the port of the bound address is randomly
|
|
3524
|
-
// assigned by the OS and would therefore not be useful for seeding.
|
|
3525
|
-
.Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0)
|
|
3526
|
-
.Finalize();
|
|
3605
|
+
uint64_t network_id = requestor.m_network_key;
|
|
3527
3606
|
const auto current_time = GetTime<std::chrono::microseconds>();
|
|
3528
|
-
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
|
|
3607
|
+
auto r = m_addr_response_caches.emplace(network_id, CachedAddrResponse{});
|
|
3529
3608
|
CachedAddrResponse& cache_entry = r.first->second;
|
|
3530
3609
|
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
|
|
3531
3610
|
cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct, /*network=*/std::nullopt);
|
|
@@ -3561,12 +3640,17 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
|
|
|
3561
3640
|
|
|
3562
3641
|
bool CConnman::AddNode(const AddedNodeParams& add)
|
|
3563
3642
|
{
|
|
3564
|
-
const CService resolved(LookupNumeric(add.m_added_node, GetDefaultPort(add.m_added_node)));
|
|
3565
|
-
const bool resolved_is_valid{resolved.IsValid()};
|
|
3643
|
+
const CService resolved{MaybeFlipIPv6toCJDNS(LookupNumeric(add.m_added_node, GetDefaultPort(add.m_added_node)))};
|
|
3644
|
+
const bool resolved_invalid{!resolved.IsValid()};
|
|
3566
3645
|
|
|
3567
3646
|
LOCK(m_added_nodes_mutex);
|
|
3568
3647
|
for (const auto& it : m_added_node_params) {
|
|
3569
|
-
if (add.m_added_node == it.m_added_node || (resolved_is_valid && resolved == LookupNumeric(it.m_added_node, GetDefaultPort(it.m_added_node)))) return false;
|
|
3648
|
+
if (add.m_added_node == it.m_added_node) return false;
|
|
3649
|
+
if (resolved_invalid) continue;
|
|
3650
|
+
const CService service{MaybeFlipIPv6toCJDNS(LookupNumeric(it.m_added_node, GetDefaultPort(it.m_added_node)))};
|
|
3651
|
+
if (resolved == service) return false;
|
|
3652
|
+
// Check if CJDNS address matches regardless of port to detect already-connected inbound peers.
|
|
3653
|
+
if (resolved.IsCJDNS() && static_cast<CNetAddr>(resolved) == static_cast<CNetAddr>(service)) return false;
|
|
3570
3654
|
}
|
|
3571
3655
|
|
|
3572
3656
|
m_added_node_params.push_back(add);
|
|
@@ -3802,6 +3886,7 @@ CNode::CNode(NodeId idIn,
|
|
|
3802
3886
|
const std::string& addrNameIn,
|
|
3803
3887
|
ConnectionType conn_type_in,
|
|
3804
3888
|
bool inbound_onion,
|
|
3889
|
+
uint64_t network_key,
|
|
3805
3890
|
CNodeOptions&& node_opts)
|
|
3806
3891
|
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
|
|
3807
3892
|
m_permission_flags{node_opts.permission_flags},
|
|
@@ -3813,7 +3898,9 @@ CNode::CNode(NodeId idIn,
|
|
|
3813
3898
|
m_dest(addrNameIn),
|
|
3814
3899
|
m_inbound_onion{inbound_onion},
|
|
3815
3900
|
m_prefer_evict{node_opts.prefer_evict},
|
|
3901
|
+
m_forced_inbound{node_opts.forced_inbound},
|
|
3816
3902
|
nKeyedNetGroup{nKeyedNetGroupIn},
|
|
3903
|
+
m_network_key{network_key},
|
|
3817
3904
|
m_conn_type{conn_type_in},
|
|
3818
3905
|
id{idIn},
|
|
3819
3906
|
nLocalHostNonce{nLocalHostNonceIn},
|
|
@@ -3875,7 +3962,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
|
|
|
3875
3962
|
AssertLockNotHeld(m_total_bytes_sent_mutex);
|
|
3876
3963
|
size_t nMessageSize = msg.data.size();
|
|
3877
3964
|
LogDebug(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
|
|
3878
|
-
if (gArgs.GetBoolArg("-capturemessages", false)) {
|
|
3965
|
+
if (m_capture_messages) {
|
|
3879
3966
|
CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false);
|
|
3880
3967
|
}
|
|
3881
3968
|
|
|
@@ -4012,6 +4099,11 @@ static void CaptureMessageToFile(const CAddress& addr,
|
|
|
4012
4099
|
uint32_t size = data.size();
|
|
4013
4100
|
ser_writedata32(f, size);
|
|
4014
4101
|
f << data;
|
|
4102
|
+
|
|
4103
|
+
if (f.fclose() != 0) {
|
|
4104
|
+
throw std::ios_base::failure(
|
|
4105
|
+
strprintf("Error closing %s after write, file contents are likely incomplete", fs::PathToString(path)));
|
|
4106
|
+
}
|
|
4015
4107
|
}
|
|
4016
4108
|
|
|
4017
4109
|
std::function<void(const CAddress& addr,
|