aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp244
1 files changed, 42 insertions, 202 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 98bd518ec..be249b446 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -9,6 +9,7 @@
#include <net.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <consensus/consensus.h>
@@ -41,8 +42,8 @@
#include <math.h>
-// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
-#define DUMP_ADDRESSES_INTERVAL 900
+// Dump addresses to peers.dat every 15 minutes (900s)
+static constexpr int DUMP_PEERS_INTERVAL = 15 * 60;
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
@@ -457,26 +458,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return pnode;
}
-void CConnman::DumpBanlist()
-{
- SweepBanned(); // clean unused entries (if bantime has expired)
-
- if (!BannedSetIsDirty())
- return;
-
- int64_t nStart = GetTimeMillis();
-
- CBanDB bandb;
- banmap_t banmap;
- GetBanned(banmap);
- if (bandb.Write(banmap)) {
- SetBannedSetDirty(false);
- }
-
- LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
-}
-
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
@@ -488,157 +469,6 @@ void CNode::CloseSocketDisconnect()
}
}
-void CConnman::ClearBanned()
-{
- {
- LOCK(cs_setBanned);
- setBanned.clear();
- setBannedIsDirty = true;
- }
- DumpBanlist(); //store banlist to disk
- if(clientInterface)
- clientInterface->BannedListChanged();
-}
-
-bool CConnman::IsBanned(CNetAddr ip)
-{
- LOCK(cs_setBanned);
- for (const auto& it : setBanned) {
- CSubNet subNet = it.first;
- CBanEntry banEntry = it.second;
-
- if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-bool CConnman::IsBanned(CSubNet subnet)
-{
- LOCK(cs_setBanned);
- banmap_t::iterator i = setBanned.find(subnet);
- if (i != setBanned.end())
- {
- CBanEntry banEntry = (*i).second;
- if (GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CSubNet subNet(addr);
- Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
-}
-
-void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CBanEntry banEntry(GetTime());
- banEntry.banReason = banReason;
- if (bantimeoffset <= 0)
- {
- bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME);
- sinceUnixEpoch = false;
- }
- banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
-
- {
- LOCK(cs_setBanned);
- if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
- setBanned[subNet] = banEntry;
- setBannedIsDirty = true;
- }
- else
- return;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
- if (subNet.Match(static_cast<CNetAddr>(pnode->addr)))
- pnode->fDisconnect = true;
- }
- }
- if(banReason == BanReasonManuallyAdded)
- DumpBanlist(); //store banlist to disk immediately if user requested ban
-}
-
-bool CConnman::Unban(const CNetAddr &addr) {
- CSubNet subNet(addr);
- return Unban(subNet);
-}
-
-bool CConnman::Unban(const CSubNet &subNet) {
- {
- LOCK(cs_setBanned);
- if (!setBanned.erase(subNet))
- return false;
- setBannedIsDirty = true;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- DumpBanlist(); //store banlist to disk immediately
- return true;
-}
-
-void CConnman::GetBanned(banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- // Sweep the banlist so expired bans are not returned
- SweepBanned();
- banMap = setBanned; //create a thread safe copy
-}
-
-void CConnman::SetBanned(const banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- setBanned = banMap;
- setBannedIsDirty = true;
-}
-
-void CConnman::SweepBanned()
-{
- int64_t now = GetTime();
- bool notifyUI = false;
- {
- LOCK(cs_setBanned);
- banmap_t::iterator it = setBanned.begin();
- while(it != setBanned.end())
- {
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
- if(now > banEntry.nBanUntil)
- {
- setBanned.erase(it++);
- setBannedIsDirty = true;
- notifyUI = true;
- LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
- }
- else
- ++it;
- }
- }
- // update UI
- if(notifyUI && clientInterface) {
- clientInterface->BannedListChanged();
- }
-}
-
-bool CConnman::BannedSetIsDirty()
-{
- LOCK(cs_setBanned);
- return setBannedIsDirty;
-}
-
-void CConnman::SetBannedSetDirty(bool dirty)
-{
- LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
- setBannedIsDirty = dirty;
-}
-
-
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
@@ -934,6 +764,7 @@ struct NodeEvictionCandidate
bool fBloomFilter;
CAddress addr;
uint64_t nKeyedNetGroup;
+ bool prefer_evict;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@@ -1002,7 +833,8 @@ bool CConnman::AttemptToEvictConnection()
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
HasAllDesirableServiceFlags(node->nServices),
- node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup};
+ node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup,
+ node->m_prefer_evict};
vEvictionCandidates.push_back(candidate);
}
}
@@ -1027,6 +859,14 @@ bool CConnman::AttemptToEvictConnection()
if (vEvictionCandidates.empty()) return false;
+ // If any remaining peers are preferred for eviction consider only them.
+ // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
+ // then we probably don't want to evict it no matter what.
+ if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
+ vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
+ [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
+ }
+
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
uint64_t naMostConnections;
@@ -1107,7 +947,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
// on all platforms. Set it again here just to be sure.
SetSocketNoDelay(hSocket);
- if (IsBanned(addr) && !whitelisted)
+ int bannedlevel = m_banman ? m_banman->IsBannedLevel(addr) : 0;
+
+ // Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept
+ // if the only banning reason was an automatic misbehavior ban.
+ if (!whitelisted && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
{
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
@@ -1131,6 +975,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
+ pnode->m_prefer_evict = bannedlevel > 0;
m_msgproc->InitializeNode(pnode);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1775,12 +1620,6 @@ void CConnman::DumpAddresses()
addrman.size(), GetTimeMillis() - nStart);
}
-void CConnman::DumpData()
-{
- DumpAddresses();
- DumpBanlist();
-}
-
void CConnman::ProcessOneShot()
{
std::string strDest;
@@ -2085,7 +1924,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
}
if (!pszDest) {
if (IsLocal(addrConnect) ||
- FindNode(static_cast<CNetAddr>(addrConnect)) || IsBanned(addrConnect) ||
+ FindNode(static_cast<CNetAddr>(addrConnect)) || (m_banman && m_banman->IsBanned(addrConnect)) ||
FindNode(addrConnect.ToStringIPPort()))
return;
} else if (FindNode(std::string(pszDest)))
@@ -2386,24 +2225,6 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
DumpAddresses();
}
}
- if (clientInterface)
- clientInterface->InitMessage(_("Loading banlist..."));
- // Load addresses from banlist.dat
- nStart = GetTimeMillis();
- CBanDB bandb;
- banmap_t banmap;
- if (bandb.Read(banmap)) {
- SetBanned(banmap); // thread save setter
- SetBannedSetDirty(false); // no need to write down, just read data
- SweepBanned(); // sweep out unused entries
-
- LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
- } else {
- LogPrintf("Invalid or missing banlist.dat; recreating\n");
- SetBannedSetDirty(true); // force write
- DumpBanlist();
- }
uiInterface.InitMessage(_("Starting network threads..."));
@@ -2457,7 +2278,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
// Dump network addresses
- scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000);
+ scheduler.scheduleEvery(std::bind(&CConnman::DumpAddresses, this), DUMP_PEERS_INTERVAL * 1000);
return true;
}
@@ -2516,7 +2337,7 @@ void CConnman::Stop()
if (fAddressesInitialized)
{
- DumpData();
+ DumpAddresses();
fAddressesInitialized = false;
}
@@ -2643,6 +2464,25 @@ bool CConnman::DisconnectNode(const std::string& strNode)
}
return false;
}
+
+bool CConnman::DisconnectNode(const CSubNet& subnet)
+{
+ bool disconnected = false;
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodes) {
+ if (subnet.Match(pnode->addr)) {
+ pnode->fDisconnect = true;
+ disconnected = true;
+ }
+ }
+ return disconnected;
+}
+
+bool CConnman::DisconnectNode(const CNetAddr& addr)
+{
+ return DisconnectNode(CSubNet(addr));
+}
+
bool CConnman::DisconnectNode(NodeId id)
{
LOCK(cs_vNodes);