Changeset View
Changeset View
Standalone View
Standalone View
src/net.cpp
Show All 35 Lines | |||||
#include <miniupnpc/upnperrors.h> | #include <miniupnpc/upnperrors.h> | ||||
#endif | #endif | ||||
#include <cmath> | #include <cmath> | ||||
// Dump addresses to peers.dat every 15 minutes (900s) | // Dump addresses to peers.dat every 15 minutes (900s) | ||||
static constexpr int DUMP_PEERS_INTERVAL = 15 * 60; | static constexpr int DUMP_PEERS_INTERVAL = 15 * 60; | ||||
// Dump addresses to banlist.dat every 15 minutes (900s) | |||||
static constexpr int DUMP_BANS_INTERVAL = 60 * 15; | |||||
// We add a random period time (0 to 1 seconds) to feeler connections to prevent | // We add a random period time (0 to 1 seconds) to feeler connections to prevent | ||||
// synchronization. | // synchronization. | ||||
#define FEELER_SLEEP_WINDOW 1 | #define FEELER_SLEEP_WINDOW 1 | ||||
// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define | // MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define | ||||
// it as 0 | // it as 0 | ||||
#if !defined(MSG_NOSIGNAL) | #if !defined(MSG_NOSIGNAL) | ||||
#define MSG_NOSIGNAL 0 | #define MSG_NOSIGNAL 0 | ||||
▲ Show 20 Lines • Show All 415 Lines • ▼ Show 20 Lines | CNode *CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, | ||||
CNode *pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, | CNode *pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, | ||||
addrConnect, CalculateKeyedNetGroup(addrConnect), | addrConnect, CalculateKeyedNetGroup(addrConnect), | ||||
nonce, addr_bind, pszDest ? pszDest : "", false); | nonce, addr_bind, pszDest ? pszDest : "", false); | ||||
pnode->AddRef(); | pnode->AddRef(); | ||||
return pnode; | return pnode; | ||||
} | } | ||||
void CConnman::DumpBanlist() { | void BanMan::DumpBanlist() { | ||||
// Clean unused entries (if bantime has expired) | // Clean unused entries (if bantime has expired) | ||||
SweepBanned(); | SweepBanned(); | ||||
if (!BannedSetIsDirty()) { | if (!BannedSetIsDirty()) { | ||||
return; | return; | ||||
} | } | ||||
int64_t nStart = GetTimeMillis(); | int64_t nStart = GetTimeMillis(); | ||||
CBanDB bandb(params); | |||||
CBanDB bandb(config->GetChainParams()); | |||||
banmap_t banmap; | banmap_t banmap; | ||||
GetBanned(banmap); | GetBanned(banmap); | ||||
if (bandb.Write(banmap)) { | if (bandb.Write(banmap)) { | ||||
SetBannedSetDirty(false); | SetBannedSetDirty(false); | ||||
} | } | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"Flushed %d banned node ips/subnets to banlist.dat %dms\n", | "Flushed %d banned node ips/subnets to banlist.dat %dms\n", | ||||
banmap.size(), GetTimeMillis() - nStart); | banmap.size(), GetTimeMillis() - nStart); | ||||
} | } | ||||
void CNode::CloseSocketDisconnect() { | void CNode::CloseSocketDisconnect() { | ||||
fDisconnect = true; | fDisconnect = true; | ||||
LOCK(cs_hSocket); | LOCK(cs_hSocket); | ||||
if (hSocket != INVALID_SOCKET) { | if (hSocket != INVALID_SOCKET) { | ||||
LogPrint(BCLog::NET, "disconnecting peer=%d\n", id); | LogPrint(BCLog::NET, "disconnecting peer=%d\n", id); | ||||
CloseSocket(hSocket); | CloseSocket(hSocket); | ||||
} | } | ||||
} | } | ||||
void CConnman::ClearBanned() { | void BanMan::ClearBanned() { | ||||
{ | { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
setBanned.clear(); | setBanned.clear(); | ||||
setBannedIsDirty = true; | setBannedIsDirty = true; | ||||
} | } | ||||
// Store banlist to disk. | // Store banlist to disk. | ||||
DumpBanlist(); | DumpBanlist(); | ||||
if (clientInterface) { | if (clientInterface) { | ||||
clientInterface->BannedListChanged(); | clientInterface->BannedListChanged(); | ||||
} | } | ||||
} | } | ||||
bool CConnman::IsBanned(CNetAddr ip) { | bool BanMan::IsBanned(CNetAddr ip) { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
for (const auto &it : setBanned) { | for (const auto &it : setBanned) { | ||||
CSubNet subNet = it.first; | CSubNet subNet = it.first; | ||||
CBanEntry banEntry = it.second; | CBanEntry banEntry = it.second; | ||||
if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) { | if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CConnman::IsBanned(CSubNet subnet) { | bool BanMan::IsBanned(CSubNet subnet) { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
banmap_t::iterator i = setBanned.find(subnet); | banmap_t::iterator i = setBanned.find(subnet); | ||||
if (i != setBanned.end()) { | if (i != setBanned.end()) { | ||||
CBanEntry banEntry = (*i).second; | CBanEntry banEntry = (*i).second; | ||||
if (GetTime() < banEntry.nBanUntil) { | if (GetTime() < banEntry.nBanUntil) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
void CConnman::Ban(const CNetAddr &addr, const BanReason &banReason, | void BanMan::Ban(const CNetAddr &addr, const BanReason &banReason, | ||||
int64_t bantimeoffset, bool sinceUnixEpoch) { | int64_t bantimeoffset, bool sinceUnixEpoch) { | ||||
CSubNet subNet(addr); | CSubNet subNet(addr); | ||||
Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); | Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); | ||||
} | } | ||||
void CConnman::Ban(const CSubNet &subNet, const BanReason &banReason, | void BanMan::Ban(const CSubNet &subNet, const BanReason &banReason, | ||||
int64_t bantimeoffset, bool sinceUnixEpoch) { | int64_t bantimeoffset, bool sinceUnixEpoch) { | ||||
CBanEntry banEntry(GetTime()); | CBanEntry banEntry(GetTime()); | ||||
banEntry.banReason = banReason; | banEntry.banReason = banReason; | ||||
if (bantimeoffset <= 0) { | if (bantimeoffset <= 0) { | ||||
bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); | bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME); | ||||
sinceUnixEpoch = false; | sinceUnixEpoch = false; | ||||
} | } | ||||
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime()) + bantimeoffset; | banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime()) + bantimeoffset; | ||||
Show All 12 Lines | void BanMan::Ban(const CSubNet &subNet, const BanReason &banReason, | ||||
} | } | ||||
if (banReason == BanReasonManuallyAdded) { | if (banReason == BanReasonManuallyAdded) { | ||||
// Store banlist to disk immediately if user requested ban. | // Store banlist to disk immediately if user requested ban. | ||||
DumpBanlist(); | DumpBanlist(); | ||||
} | } | ||||
} | } | ||||
bool CConnman::Unban(const CNetAddr &addr) { | bool BanMan::Unban(const CNetAddr &addr) { | ||||
CSubNet subNet(addr); | CSubNet subNet(addr); | ||||
return Unban(subNet); | return Unban(subNet); | ||||
} | } | ||||
bool CConnman::Unban(const CSubNet &subNet) { | bool BanMan::Unban(const CSubNet &subNet) { | ||||
{ | { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
if (!setBanned.erase(subNet)) { | if (!setBanned.erase(subNet)) { | ||||
return false; | return false; | ||||
} | } | ||||
setBannedIsDirty = true; | setBannedIsDirty = true; | ||||
} | } | ||||
if (clientInterface) { | if (clientInterface) { | ||||
clientInterface->BannedListChanged(); | clientInterface->BannedListChanged(); | ||||
} | } | ||||
// Store banlist to disk immediately. | // Store banlist to disk immediately. | ||||
DumpBanlist(); | DumpBanlist(); | ||||
return true; | return true; | ||||
} | } | ||||
void CConnman::GetBanned(banmap_t &banMap) { | void BanMan::GetBanned(banmap_t &banMap) { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
// Sweep the banlist so expired bans are not returned | // Sweep the banlist so expired bans are not returned | ||||
SweepBanned(); | SweepBanned(); | ||||
// Create a thread safe copy. | // Create a thread safe copy. | ||||
banMap = setBanned; | banMap = setBanned; | ||||
} | } | ||||
void CConnman::SetBanned(const banmap_t &banMap) { | void BanMan::SetBanned(const banmap_t &banMap) { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
setBanned = banMap; | setBanned = banMap; | ||||
setBannedIsDirty = true; | setBannedIsDirty = true; | ||||
} | } | ||||
void CConnman::SweepBanned() { | void BanMan::SweepBanned() { | ||||
int64_t now = GetTime(); | int64_t now = GetTime(); | ||||
bool notifyUI = false; | bool notifyUI = false; | ||||
{ | { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
banmap_t::iterator it = setBanned.begin(); | banmap_t::iterator it = setBanned.begin(); | ||||
while (it != setBanned.end()) { | while (it != setBanned.end()) { | ||||
CSubNet subNet = (*it).first; | CSubNet subNet = (*it).first; | ||||
CBanEntry banEntry = (*it).second; | CBanEntry banEntry = (*it).second; | ||||
Show All 12 Lines | void BanMan::SweepBanned() { | ||||
} | } | ||||
// update UI | // update UI | ||||
if (notifyUI && clientInterface) { | if (notifyUI && clientInterface) { | ||||
clientInterface->BannedListChanged(); | clientInterface->BannedListChanged(); | ||||
} | } | ||||
} | } | ||||
bool CConnman::BannedSetIsDirty() { | bool BanMan::BannedSetIsDirty() { | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
return setBannedIsDirty; | return setBannedIsDirty; | ||||
} | } | ||||
void CConnman::SetBannedSetDirty(bool dirty) { | void BanMan::SetBannedSetDirty(bool dirty) { | ||||
// Reuse setBanned lock for the isDirty flag. | // Reuse setBanned lock for the isDirty flag. | ||||
LOCK(cs_setBanned); | LOCK(cs_setBanned); | ||||
setBannedIsDirty = dirty; | setBannedIsDirty = dirty; | ||||
} | } | ||||
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { | bool CConnman::IsWhitelistedRange(const CNetAddr &addr) { | ||||
for (const CSubNet &subnet : vWhitelistedRange) { | for (const CSubNet &subnet : vWhitelistedRange) { | ||||
if (subnet.Match(addr)) { | if (subnet.Match(addr)) { | ||||
▲ Show 20 Lines • Show All 523 Lines • ▼ Show 20 Lines | if (!IsSelectableSocket(hSocket)) { | ||||
CloseSocket(hSocket); | CloseSocket(hSocket); | ||||
return; | return; | ||||
} | } | ||||
// According to the internet TCP_NODELAY is not carried into accepted | // According to the internet TCP_NODELAY is not carried into accepted | ||||
// sockets on all platforms. Set it again here just to be sure. | // sockets on all platforms. Set it again here just to be sure. | ||||
SetSocketNoDelay(hSocket); | SetSocketNoDelay(hSocket); | ||||
if (IsBanned(addr) && !whitelisted) { | if (m_banman && m_banman->IsBanned(addr) && !whitelisted) { | ||||
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", | LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", | ||||
addr.ToString()); | addr.ToString()); | ||||
CloseSocket(hSocket); | CloseSocket(hSocket); | ||||
return; | return; | ||||
} | } | ||||
if (nInbound >= nMaxInbound) { | if (nInbound >= nMaxInbound) { | ||||
if (!AttemptToEvictConnection()) { | if (!AttemptToEvictConnection()) { | ||||
▲ Show 20 Lines • Show All 899 Lines • ▼ Show 20 Lines | if (interruptNet) { | ||||
return; | return; | ||||
} | } | ||||
if (!fNetworkActive) { | if (!fNetworkActive) { | ||||
return; | return; | ||||
} | } | ||||
if (!pszDest) { | if (!pszDest) { | ||||
if (IsLocal(addrConnect) || | if (IsLocal(addrConnect) || | ||||
FindNode(static_cast<CNetAddr>(addrConnect)) || | FindNode(static_cast<CNetAddr>(addrConnect)) || | ||||
IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) { | (m_banman && m_banman->IsBanned(addrConnect)) || | ||||
FindNode(addrConnect.ToStringIPPort())) { | |||||
return; | return; | ||||
} | } | ||||
} else if (FindNode(std::string(pszDest))) { | } else if (FindNode(std::string(pszDest))) { | ||||
return; | return; | ||||
} | } | ||||
CNode *pnode = | CNode *pnode = | ||||
ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection); | ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection); | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | int64_t nStart = GetTimeMillis(); | ||||
addrman.size(), GetTimeMillis() - nStart); | addrman.size(), GetTimeMillis() - nStart); | ||||
} else { | } else { | ||||
// Addrman can be in an inconsistent state after failure, reset it | // Addrman can be in an inconsistent state after failure, reset it | ||||
addrman.Clear(); | addrman.Clear(); | ||||
LogPrintf("Invalid or missing peers.dat; recreating\n"); | LogPrintf("Invalid or missing peers.dat; recreating\n"); | ||||
DumpAddresses(); | DumpAddresses(); | ||||
} | } | ||||
} | } | ||||
if (clientInterface) { | |||||
clientInterface->InitMessage(_("Loading banlist...")); | |||||
} | |||||
// Load addresses from banlist.dat | |||||
nStart = GetTimeMillis(); | |||||
CBanDB bandb(config->GetChainParams()); | |||||
banmap_t banmap; | |||||
if (bandb.Read(banmap)) { | |||||
// thread save setter | |||||
SetBanned(banmap); | |||||
// no need to write down, just read data | |||||
SetBannedSetDirty(false); | |||||
// sweep out unused entries | |||||
SweepBanned(); | |||||
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"); | |||||
// force write | |||||
SetBannedSetDirty(true); | |||||
DumpBanlist(); | |||||
} | |||||
uiInterface.InitMessage(_("Starting network threads...")); | uiInterface.InitMessage(_("Starting network threads...")); | ||||
fAddressesInitialized = true; | fAddressesInitialized = true; | ||||
if (semOutbound == nullptr) { | if (semOutbound == nullptr) { | ||||
// initialize semaphore | // initialize semaphore | ||||
semOutbound = std::make_unique<CSemaphore>( | semOutbound = std::make_unique<CSemaphore>( | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | bool CConnman::Start(CScheduler &scheduler, const Options &connOptions) { | ||||
// Dump network addresses | // Dump network addresses | ||||
scheduler.scheduleEvery( | scheduler.scheduleEvery( | ||||
[this]() { | [this]() { | ||||
this->DumpAddresses(); | this->DumpAddresses(); | ||||
return true; | return true; | ||||
}, | }, | ||||
DUMP_PEERS_INTERVAL * 1000); | DUMP_PEERS_INTERVAL * 1000); | ||||
scheduler.scheduleEvery( | |||||
[this]() { | |||||
this->DumpBanlist(); | |||||
return true; | return true; | ||||
}, | } | ||||
DUMP_BANS_INTERVAL * 1000); | |||||
return true; | BanMan::BanMan(const CChainParams &_params, | ||||
CClientUIInterface *client_interface) | |||||
: clientInterface(client_interface), params(_params) { | |||||
if (clientInterface) { | |||||
clientInterface->InitMessage(_("Loading banlist...")); | |||||
} | |||||
// Load addresses from banlist.dat | |||||
int64_t nStart = GetTimeMillis(); | |||||
setBannedIsDirty = false; | |||||
CBanDB bandb(params); | |||||
banmap_t banmap; | |||||
if (bandb.Read(banmap)) { | |||||
// thread save setter | |||||
SetBanned(banmap); | |||||
// no need to write down, just read data | |||||
SetBannedSetDirty(false); | |||||
// sweep out unused entries | |||||
SweepBanned(); | |||||
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"); | |||||
// force write | |||||
SetBannedSetDirty(true); | |||||
DumpBanlist(); | |||||
} | |||||
} | |||||
BanMan::~BanMan() { | |||||
DumpBanlist(); | |||||
} | } | ||||
class CNetCleanup { | class CNetCleanup { | ||||
public: | public: | ||||
CNetCleanup() {} | CNetCleanup() {} | ||||
~CNetCleanup() { | ~CNetCleanup() { | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
Show All 40 Lines | if (threadDNSAddressSeed.joinable()) { | ||||
threadDNSAddressSeed.join(); | threadDNSAddressSeed.join(); | ||||
} | } | ||||
if (threadSocketHandler.joinable()) { | if (threadSocketHandler.joinable()) { | ||||
threadSocketHandler.join(); | threadSocketHandler.join(); | ||||
} | } | ||||
if (fAddressesInitialized) { | if (fAddressesInitialized) { | ||||
DumpAddresses(); | DumpAddresses(); | ||||
DumpBanlist(); | |||||
fAddressesInitialized = false; | fAddressesInitialized = false; | ||||
} | } | ||||
// Close sockets | // Close sockets | ||||
for (CNode *pnode : vNodes) { | for (CNode *pnode : vNodes) { | ||||
pnode->CloseSocketDisconnect(); | pnode->CloseSocketDisconnect(); | ||||
} | } | ||||
for (ListenSocket &hListenSocket : vhListenSocket) { | for (ListenSocket &hListenSocket : vhListenSocket) { | ||||
▲ Show 20 Lines • Show All 461 Lines • Show Last 20 Lines |