|
16 | 16 | #include <net_permissions.h>
|
17 | 17 | #include <netbase.h>
|
18 | 18 | #include <node/ui_interface.h>
|
| 19 | +#include <optional.h> |
19 | 20 | #include <protocol.h>
|
20 | 21 | #include <random.h>
|
21 | 22 | #include <scheduler.h>
|
@@ -840,21 +841,6 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno
|
840 | 841 | return nSentSize;
|
841 | 842 | }
|
842 | 843 |
|
843 |
| -struct NodeEvictionCandidate |
844 |
| -{ |
845 |
| - NodeId id; |
846 |
| - int64_t nTimeConnected; |
847 |
| - int64_t nMinPingUsecTime; |
848 |
| - int64_t nLastBlockTime; |
849 |
| - int64_t nLastTXTime; |
850 |
| - bool fRelevantServices; |
851 |
| - bool fRelayTxes; |
852 |
| - bool fBloomFilter; |
853 |
| - uint64_t nKeyedNetGroup; |
854 |
| - bool prefer_evict; |
855 |
| - bool m_is_local; |
856 |
| -}; |
857 |
| - |
858 | 844 | static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
|
859 | 845 | {
|
860 | 846 | return a.nMinPingUsecTime > b.nMinPingUsecTime;
|
@@ -910,43 +896,8 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator,
|
910 | 896 | elements.erase(elements.end() - eraseSize, elements.end());
|
911 | 897 | }
|
912 | 898 |
|
913 |
| -/** Try to find a connection to evict when the node is full. |
914 |
| - * Extreme care must be taken to avoid opening the node to attacker |
915 |
| - * triggered network partitioning. |
916 |
| - * The strategy used here is to protect a small number of peers |
917 |
| - * for each of several distinct characteristics which are difficult |
918 |
| - * to forge. In order to partition a node the attacker must be |
919 |
| - * simultaneously better at all of them than honest peers. |
920 |
| - */ |
921 |
| -bool CConnman::AttemptToEvictConnection() |
| 899 | +[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates) |
922 | 900 | {
|
923 |
| - std::vector<NodeEvictionCandidate> vEvictionCandidates; |
924 |
| - { |
925 |
| - LOCK(cs_vNodes); |
926 |
| - |
927 |
| - for (const CNode* node : vNodes) { |
928 |
| - if (node->HasPermission(PF_NOBAN)) |
929 |
| - continue; |
930 |
| - if (!node->IsInboundConn()) |
931 |
| - continue; |
932 |
| - if (node->fDisconnect) |
933 |
| - continue; |
934 |
| - bool peer_relay_txes = false; |
935 |
| - bool peer_filter_not_null = false; |
936 |
| - if (node->m_tx_relay != nullptr) { |
937 |
| - LOCK(node->m_tx_relay->cs_filter); |
938 |
| - peer_relay_txes = node->m_tx_relay->fRelayTxes; |
939 |
| - peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; |
940 |
| - } |
941 |
| - NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, |
942 |
| - node->nLastBlockTime, node->nLastTXTime, |
943 |
| - HasAllDesirableServiceFlags(node->nServices), |
944 |
| - peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup, |
945 |
| - node->m_prefer_evict, node->addr.IsLocal()}; |
946 |
| - vEvictionCandidates.push_back(candidate); |
947 |
| - } |
948 |
| - } |
949 |
| - |
950 | 901 | // Protect connections with certain characteristics
|
951 | 902 |
|
952 | 903 | // Deterministically select 4 peers to protect by netgroup.
|
@@ -984,7 +935,7 @@ bool CConnman::AttemptToEvictConnection()
|
984 | 935 | total_protect_size -= initial_size - vEvictionCandidates.size();
|
985 | 936 | EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size);
|
986 | 937 |
|
987 |
| - if (vEvictionCandidates.empty()) return false; |
| 938 | + if (vEvictionCandidates.empty()) return nullopt; |
988 | 939 |
|
989 | 940 | // If any remaining peers are preferred for eviction consider only them.
|
990 | 941 | // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
|
@@ -1016,10 +967,52 @@ bool CConnman::AttemptToEvictConnection()
|
1016 | 967 | vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
|
1017 | 968 |
|
1018 | 969 | // Disconnect from the network group with the most connections
|
1019 |
| - NodeId evicted = vEvictionCandidates.front().id; |
| 970 | + return vEvictionCandidates.front().id; |
| 971 | +} |
| 972 | + |
| 973 | +/** Try to find a connection to evict when the node is full. |
| 974 | + * Extreme care must be taken to avoid opening the node to attacker |
| 975 | + * triggered network partitioning. |
| 976 | + * The strategy used here is to protect a small number of peers |
| 977 | + * for each of several distinct characteristics which are difficult |
| 978 | + * to forge. In order to partition a node the attacker must be |
| 979 | + * simultaneously better at all of them than honest peers. |
| 980 | + */ |
| 981 | +bool CConnman::AttemptToEvictConnection() |
| 982 | +{ |
| 983 | + std::vector<NodeEvictionCandidate> vEvictionCandidates; |
| 984 | + { |
| 985 | + |
| 986 | + LOCK(cs_vNodes); |
| 987 | + for (const CNode* node : vNodes) { |
| 988 | + if (node->HasPermission(PF_NOBAN)) |
| 989 | + continue; |
| 990 | + if (!node->IsInboundConn()) |
| 991 | + continue; |
| 992 | + if (node->fDisconnect) |
| 993 | + continue; |
| 994 | + bool peer_relay_txes = false; |
| 995 | + bool peer_filter_not_null = false; |
| 996 | + if (node->m_tx_relay != nullptr) { |
| 997 | + LOCK(node->m_tx_relay->cs_filter); |
| 998 | + peer_relay_txes = node->m_tx_relay->fRelayTxes; |
| 999 | + peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; |
| 1000 | + } |
| 1001 | + NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, |
| 1002 | + node->nLastBlockTime, node->nLastTXTime, |
| 1003 | + HasAllDesirableServiceFlags(node->nServices), |
| 1004 | + peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup, |
| 1005 | + node->m_prefer_evict, node->addr.IsLocal()}; |
| 1006 | + vEvictionCandidates.push_back(candidate); |
| 1007 | + } |
| 1008 | + } |
| 1009 | + const Optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates)); |
| 1010 | + if (!node_id_to_evict) { |
| 1011 | + return false; |
| 1012 | + } |
1020 | 1013 | LOCK(cs_vNodes);
|
1021 | 1014 | for (CNode* pnode : vNodes) {
|
1022 |
| - if (pnode->GetId() == evicted) { |
| 1015 | + if (pnode->GetId() == *node_id_to_evict) { |
1023 | 1016 | pnode->fDisconnect = true;
|
1024 | 1017 | return true;
|
1025 | 1018 | }
|
|
0 commit comments