src/net.cpp
/** 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.
 */
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.
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() {
    std::vector<NodeEvictionCandidate> vEvictionCandidates;
    {
        LOCK(cs_vNodes);
        BOOST_FOREACH(CNode *node, vNodes) {
            if (node->fWhitelisted)
                continue;
            if (!node->fInbound)
                continue;
            if (node->fDisconnect)
                continue;
            NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime,
                                               node->nLastBlockTime, node->nLastTXTime,
                                               (node->nServices & nRelevantServices) == nRelevantServices,
                                               node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup};
            vEvictionCandidates.push_back(candidate);
        }
    }
    if (vEvictionCandidates.empty()) return false;
    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed);
    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
    if (vEvictionCandidates.empty()) return false;
    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
    if (vEvictionCandidates.empty()) return false;
    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);
    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
    if (vEvictionCandidates.empty()) return false;
    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);
    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
    if (vEvictionCandidates.empty()) return false;
    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
    vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
    if (vEvictionCandidates.empty()) return false;
    uint64_t naMostConnections;
    unsigned int nMostConnections = 0;
    int64_t nMostConnectionsTime = 0;
    std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapAddrCounts;
    BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) {
        mapAddrCounts[node.nKeyedNetGroup].push_back(node);
        int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected;
        size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size();
        if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
            nMostConnections = groupsize;
            nMostConnectionsTime = grouptime;
            naMostConnections = node.nKeyedNetGroup;
        }
    }
    vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]);
    NodeId evicted = vEvictionCandidates.front().id;
    LOCK(cs_vNodes);
    for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
        if ((*it)->GetId() == evicted) {
            (*it)->fDisconnect = true;
            return true;
        }
    }
    return false;
}
static bool AttemptToEvictConnection ( ) { std :: vector < NodeEvictionCandidate > vEvictionCandidates ; { LOCK ( cs_vNodes ) ; BOOST_FOREACH ( CNode * node , vNodes ) { if ( node -> fWhitelisted ) continue ; if ( ! node -> fInbound ) continue ; if ( node -> fDisconnect ) continue ; NodeEvictionCandidate candidate = { node -> id , node -> nTimeConnected , node -> nMinPingUsecTime , node -> nLastBlockTime , node -> nLastTXTime , ( node -> nServices & nRelevantServices ) == nRelevantServices , node -> fRelayTxes , node -> pfilter != NULL , node -> addr , node -> nKeyedNetGroup } ; vEvictionCandidates . push_back ( candidate ) ; } } if ( vEvictionCandidates . empty ( ) ) return false ; std :: sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNetGroupKeyed ) ; vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std :: min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ; if ( vEvictionCandidates . empty ( ) ) return false ; std :: sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeMinPingTime ) ; vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std :: min ( 8 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ; if ( vEvictionCandidates . empty ( ) ) return false ; std :: sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNodeTXTime ) ; vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std :: min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ; if ( vEvictionCandidates . empty ( ) ) return false ; std :: sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , CompareNodeBlockTime ) ; vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - std :: min ( 4 , static_cast < int > ( vEvictionCandidates . size ( ) ) ) , vEvictionCandidates . end ( ) ) ; if ( vEvictionCandidates . empty ( ) ) return false ; std :: sort ( vEvictionCandidates . begin ( ) , vEvictionCandidates . end ( ) , ReverseCompareNodeTimeConnected ) ; vEvictionCandidates . erase ( vEvictionCandidates . end ( ) - static_cast < int > ( vEvictionCandidates . size ( ) / 2 ) , vEvictionCandidates . end ( ) ) ; if ( vEvictionCandidates . empty ( ) ) return false ; uint64_t naMostConnections ; unsigned int nMostConnections = 0 ; int64_t nMostConnectionsTime = 0 ; std :: map < uint64_t , std :: vector < NodeEvictionCandidate > > mapAddrCounts ; BOOST_FOREACH ( const NodeEvictionCandidate & node , vEvictionCandidates ) { mapAddrCounts [ node . nKeyedNetGroup ] . push_back ( node ) ; int64_t grouptime = mapAddrCounts [ node . nKeyedNetGroup ] [ 0 ] . nTimeConnected ; size_t groupsize = mapAddrCounts [ node . nKeyedNetGroup ] . size ( ) ; if ( groupsize > nMostConnections || ( groupsize == nMostConnections && grouptime > nMostConnectionsTime ) ) { nMostConnections = groupsize ; nMostConnectionsTime = grouptime ; naMostConnections = node . nKeyedNetGroup ; } } vEvictionCandidates = std :: move ( mapAddrCounts [ naMostConnections ] ) ; NodeId evicted = vEvictionCandidates . front ( ) . id ; LOCK ( cs_vNodes ) ; for ( std :: vector < CNode * > :: const_iterator it ( vNodes . begin ( ) ) ; it != vNodes . end ( ) ; ++ it ) { if ( ( * it ) -> GetId ( ) == evicted ) { ( * it ) -> fDisconnect = true ; return true ; } } return false ; }
Try to find a connection to evict when the node is full.
Try to find a connection to evict when the node is full .
// Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. // An attacker cannot predict which netgroups will be protected // Protect the 8 nodes with the lowest minimum ping time. // An attacker cannot manipulate this metric without physically moving nodes closer to the target. // Protect 4 nodes that most recently sent us transactions. // An attacker cannot manipulate this metric without performing useful work. // Protect 4 nodes that most recently sent us blocks. // An attacker cannot manipulate this metric without performing useful work. // Protect the half of the remaining nodes which have been connected the longest. // This replicates the non-eviction implicit behavior, and precludes attacks that start later. // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) // Reduce to the network group with the most connections // Disconnect from the network group with the most connections