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
| 998 | * simultaneously better at all of them than honest peers. |
| 999 | */ |
| 1000 | bool CConnman::AttemptToEvictConnection() |
| 1001 | { |
| 1002 | std::vector<NodeEvictionCandidate> vEvictionCandidates; |
| 1003 | { |
| 1004 | LOCK(cs_vNodes); |
| 1005 | |
| 1006 | for (const CNode* node : vNodes) { |
| 1007 | if (node->fWhitelisted) |
| 1008 | continue; |
| 1009 | if (!node->fInbound) |
| 1010 | continue; |
| 1011 | if (node->fDisconnect) |
| 1012 | continue; |
| 1013 | NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, |
| 1014 | node->nLastBlockTime, node->nLastTXTime, |
| 1015 | HasAllDesirableServiceFlags(node->nServices), |
| 1016 | node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup}; |
| 1017 | vEvictionCandidates.push_back(candidate); |
| 1018 | } |
| 1019 | } |
| 1020 | |
| 1021 | // Protect connections with certain characteristics |
| 1022 | |
| 1023 | // Deterministically select 4 peers to protect by netgroup. |
| 1024 | // An attacker cannot predict which netgroups will be protected |
| 1025 | EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4); |
| 1026 | // Protect the 8 nodes with the lowest minimum ping time. |
| 1027 | // An attacker cannot manipulate this metric without physically moving nodes closer to the target. |
| 1028 | EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8); |
| 1029 | // Protect 4 nodes that most recently sent us transactions. |
| 1030 | // An attacker cannot manipulate this metric without performing useful work. |
| 1031 | EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4); |
| 1032 | // Protect 4 nodes that most recently sent us blocks. |
| 1033 | // An attacker cannot manipulate this metric without performing useful work. |
| 1034 | EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4); |
| 1035 | // Protect the half of the remaining nodes which have been connected the longest. |
| 1036 | // This replicates the non-eviction implicit behavior, and precludes attacks that start later. |
| 1037 | EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2); |
| 1038 | |
| 1039 | if (vEvictionCandidates.empty()) return false; |
| 1040 | |
| 1041 | // Identify the network group with the most connections and youngest member. |
| 1042 | // (vEvictionCandidates is already sorted by reverse connect time) |
| 1043 | uint64_t naMostConnections; |
| 1044 | unsigned int nMostConnections = 0; |
| 1045 | int64_t nMostConnectionsTime = 0; |
| 1046 | std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes; |
| 1047 | for (const NodeEvictionCandidate &node : vEvictionCandidates) { |
| 1048 | std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup]; |
| 1049 | group.push_back(node); |
| 1050 | int64_t grouptime = group[0].nTimeConnected; |
| 1051 | |
| 1052 | if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) { |
| 1053 | nMostConnections = group.size(); |
| 1054 | nMostConnectionsTime = grouptime; |
| 1055 | naMostConnections = node.nKeyedNetGroup; |
| 1056 | } |
| 1057 | } |
nothing calls this directly
no test coverage detected