|
|
@ -877,6 +877,14 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Try to find a connection to evict when the node is full.
|
|
|
|
|
|
|
|
* Extreme care must be taken to avoid opening the node to attacker |
|
|
|
|
|
|
|
* triggered network partitioning. |
|
|
|
|
|
|
|
* The strategy used here is to protect a small number of peers |
|
|
|
|
|
|
|
* for each of several distinct characteristics which are difficult |
|
|
|
|
|
|
|
* to forge. In order to partition a node the attacker must be |
|
|
|
|
|
|
|
* simultaneously better at all of them than honest peers. |
|
|
|
|
|
|
|
*/ |
|
|
|
static bool AttemptToEvictConnection(bool fPreferNewConnection) { |
|
|
|
static bool AttemptToEvictConnection(bool fPreferNewConnection) { |
|
|
|
std::vector<CNodeRef> vEvictionCandidates; |
|
|
|
std::vector<CNodeRef> vEvictionCandidates; |
|
|
|
{ |
|
|
|
{ |
|
|
@ -905,7 +913,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { |
|
|
|
|
|
|
|
|
|
|
|
if (vEvictionCandidates.empty()) return false; |
|
|
|
if (vEvictionCandidates.empty()) return false; |
|
|
|
|
|
|
|
|
|
|
|
// Protect the 8 nodes with the best ping times.
|
|
|
|
// Protect the 8 nodes with the lowest minimum ping time.
|
|
|
|
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
|
|
|
|
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
|
|
|
|
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime); |
|
|
|
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime); |
|
|
|
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); |
|
|
|
vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end()); |
|
|
@ -913,7 +921,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { |
|
|
|
if (vEvictionCandidates.empty()) return false; |
|
|
|
if (vEvictionCandidates.empty()) return false; |
|
|
|
|
|
|
|
|
|
|
|
// Protect the half of the remaining nodes which have been connected the longest.
|
|
|
|
// Protect the half of the remaining nodes which have been connected the longest.
|
|
|
|
// This replicates the existing implicit behavior.
|
|
|
|
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
|
|
|
|
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); |
|
|
|
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected); |
|
|
|
vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); |
|
|
|
vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end()); |
|
|
|
|
|
|
|
|
|
|
@ -941,6 +949,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { |
|
|
|
vEvictionCandidates = mapAddrCounts[naMostConnections]; |
|
|
|
vEvictionCandidates = mapAddrCounts[naMostConnections]; |
|
|
|
|
|
|
|
|
|
|
|
// Do not disconnect peers if there is only one unprotected connection from their network group.
|
|
|
|
// Do not disconnect peers if there is only one unprotected connection from their network group.
|
|
|
|
|
|
|
|
// This step excessively favors netgroup diversity, and should be removed once more protective criteria are established.
|
|
|
|
if (vEvictionCandidates.size() <= 1) |
|
|
|
if (vEvictionCandidates.size() <= 1) |
|
|
|
// unless we prefer the new connection (for whitelisted peers)
|
|
|
|
// unless we prefer the new connection (for whitelisted peers)
|
|
|
|
if (!fPreferNewConnection) |
|
|
|
if (!fPreferNewConnection) |
|
|
|