|
|
@ -445,11 +445,13 @@ void CNode::PushVersion() |
|
|
|
|
|
|
|
|
|
|
|
std::map<CSubNet, int64_t> CNode::setBanned; |
|
|
|
std::map<CSubNet, int64_t> CNode::setBanned; |
|
|
|
CCriticalSection CNode::cs_setBanned; |
|
|
|
CCriticalSection CNode::cs_setBanned; |
|
|
|
|
|
|
|
bool CNode::setBannedIsDirty; |
|
|
|
|
|
|
|
|
|
|
|
void CNode::ClearBanned() |
|
|
|
void CNode::ClearBanned() |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(cs_setBanned); |
|
|
|
LOCK(cs_setBanned); |
|
|
|
setBanned.clear(); |
|
|
|
setBanned.clear(); |
|
|
|
|
|
|
|
setBannedIsDirty = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool CNode::IsBanned(CNetAddr ip) |
|
|
|
bool CNode::IsBanned(CNetAddr ip) |
|
|
@ -498,6 +500,8 @@ void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoc |
|
|
|
LOCK(cs_setBanned); |
|
|
|
LOCK(cs_setBanned); |
|
|
|
if (setBanned[subNet] < banTime) |
|
|
|
if (setBanned[subNet] < banTime) |
|
|
|
setBanned[subNet] = banTime; |
|
|
|
setBanned[subNet] = banTime; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setBannedIsDirty = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool CNode::Unban(const CNetAddr &addr) { |
|
|
|
bool CNode::Unban(const CNetAddr &addr) { |
|
|
@ -508,7 +512,10 @@ bool CNode::Unban(const CNetAddr &addr) { |
|
|
|
bool CNode::Unban(const CSubNet &subNet) { |
|
|
|
bool CNode::Unban(const CSubNet &subNet) { |
|
|
|
LOCK(cs_setBanned); |
|
|
|
LOCK(cs_setBanned); |
|
|
|
if (setBanned.erase(subNet)) |
|
|
|
if (setBanned.erase(subNet)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
setBannedIsDirty = true; |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -518,6 +525,43 @@ void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap) |
|
|
|
banMap = setBanned; //create a thread safe copy
|
|
|
|
banMap = setBanned; //create a thread safe copy
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CNode::SetBanned(const std::map<CSubNet, int64_t> &banMap) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LOCK(cs_setBanned); |
|
|
|
|
|
|
|
setBanned = banMap; |
|
|
|
|
|
|
|
setBannedIsDirty = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CNode::SweepBanned() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int64_t now = GetTime(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOCK(cs_setBanned); |
|
|
|
|
|
|
|
std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); |
|
|
|
|
|
|
|
while(it != setBanned.end()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(now > (*it).second) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
setBanned.erase(it++); |
|
|
|
|
|
|
|
setBannedIsDirty = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
++it; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CNode::BannedSetIsDirty() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LOCK(cs_setBanned); |
|
|
|
|
|
|
|
return setBannedIsDirty; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CNode::SetBannedSetDirty(bool dirty) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
|
|
|
|
|
|
|
|
setBannedIsDirty = dirty; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<CSubNet> CNode::vWhitelistedRange; |
|
|
|
std::vector<CSubNet> CNode::vWhitelistedRange; |
|
|
|
CCriticalSection CNode::cs_vWhitelistedRange; |
|
|
|
CCriticalSection CNode::cs_vWhitelistedRange; |
|
|
@ -1212,6 +1256,17 @@ void DumpAddresses() |
|
|
|
addrman.size(), GetTimeMillis() - nStart); |
|
|
|
addrman.size(), GetTimeMillis() - nStart); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DumpData() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
DumpAddresses(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (CNode::BannedSetIsDirty()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
DumpBanlist(); |
|
|
|
|
|
|
|
CNode::SetBannedSetDirty(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void static ProcessOneShot() |
|
|
|
void static ProcessOneShot() |
|
|
|
{ |
|
|
|
{ |
|
|
|
string strDest; |
|
|
|
string strDest; |
|
|
@ -1650,6 +1705,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) |
|
|
|
if (!adb.Read(addrman)) |
|
|
|
if (!adb.Read(addrman)) |
|
|
|
LogPrintf("Invalid or missing peers.dat; recreating\n"); |
|
|
|
LogPrintf("Invalid or missing peers.dat; recreating\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//try to read stored banlist
|
|
|
|
|
|
|
|
CBanDB bandb; |
|
|
|
|
|
|
|
std::map<CSubNet, int64_t> banmap; |
|
|
|
|
|
|
|
if (!bandb.Read(banmap)) |
|
|
|
|
|
|
|
LogPrintf("Invalid or missing banlist.dat; recreating\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CNode::SetBanned(banmap); //thread save setter
|
|
|
|
|
|
|
|
CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data
|
|
|
|
|
|
|
|
CNode::SweepBanned(); //sweap out unused entries
|
|
|
|
|
|
|
|
|
|
|
|
LogPrintf("Loaded %i addresses from peers.dat %dms\n", |
|
|
|
LogPrintf("Loaded %i addresses from peers.dat %dms\n", |
|
|
|
addrman.size(), GetTimeMillis() - nStart); |
|
|
|
addrman.size(), GetTimeMillis() - nStart); |
|
|
|
fAddressesInitialized = true; |
|
|
|
fAddressesInitialized = true; |
|
|
@ -1690,7 +1756,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) |
|
|
|
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler)); |
|
|
|
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler)); |
|
|
|
|
|
|
|
|
|
|
|
// Dump network addresses
|
|
|
|
// Dump network addresses
|
|
|
|
scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL); |
|
|
|
scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool StopNode() |
|
|
|
bool StopNode() |
|
|
@ -1703,7 +1769,7 @@ bool StopNode() |
|
|
|
|
|
|
|
|
|
|
|
if (fAddressesInitialized) |
|
|
|
if (fAddressesInitialized) |
|
|
|
{ |
|
|
|
{ |
|
|
|
DumpAddresses(); |
|
|
|
DumpData(); |
|
|
|
fAddressesInitialized = false; |
|
|
|
fAddressesInitialized = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2107,3 +2173,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) |
|
|
|
|
|
|
|
|
|
|
|
LEAVE_CRITICAL_SECTION(cs_vSend); |
|
|
|
LEAVE_CRITICAL_SECTION(cs_vSend); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// CBanDB
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBanDB::CBanDB() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
pathBanlist = GetDataDir() / "banlist.dat"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBanDB::Write(const std::map<CSubNet, int64_t>& banSet) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Generate random temporary filename
|
|
|
|
|
|
|
|
unsigned short randv = 0; |
|
|
|
|
|
|
|
GetRandBytes((unsigned char*)&randv, sizeof(randv)); |
|
|
|
|
|
|
|
std::string tmpfn = strprintf("banlist.dat.%04x", randv); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// serialize banlist, checksum data up to that point, then append csum
|
|
|
|
|
|
|
|
CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
ssBanlist << FLATDATA(Params().MessageStart()); |
|
|
|
|
|
|
|
ssBanlist << banSet; |
|
|
|
|
|
|
|
uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); |
|
|
|
|
|
|
|
ssBanlist << hash; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// open temp output file, and associate with CAutoFile
|
|
|
|
|
|
|
|
boost::filesystem::path pathTmp = GetDataDir() / tmpfn; |
|
|
|
|
|
|
|
FILE *file = fopen(pathTmp.string().c_str(), "wb"); |
|
|
|
|
|
|
|
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
if (fileout.IsNull()) |
|
|
|
|
|
|
|
return error("%s: Failed to open file %s", __func__, pathTmp.string()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Write and commit header, data
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
fileout << ssBanlist; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (const std::exception& e) { |
|
|
|
|
|
|
|
return error("%s: Serialize or I/O error - %s", __func__, e.what()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
FileCommit(fileout.Get()); |
|
|
|
|
|
|
|
fileout.fclose(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// replace existing banlist.dat, if any, with new banlist.dat.XXXX
|
|
|
|
|
|
|
|
if (!RenameOver(pathTmp, pathBanlist)) |
|
|
|
|
|
|
|
return error("%s: Rename-into-place failed", __func__); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBanDB::Read(std::map<CSubNet, int64_t>& banSet) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// open input file, and associate with CAutoFile
|
|
|
|
|
|
|
|
FILE *file = fopen(pathBanlist.string().c_str(), "rb"); |
|
|
|
|
|
|
|
CAutoFile filein(file, SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
if (filein.IsNull()) |
|
|
|
|
|
|
|
return error("%s: Failed to open file %s", __func__, pathBanlist.string()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// use file size to size memory buffer
|
|
|
|
|
|
|
|
int fileSize = boost::filesystem::file_size(pathBanlist); |
|
|
|
|
|
|
|
int dataSize = fileSize - sizeof(uint256); |
|
|
|
|
|
|
|
// Don't try to resize to a negative number if file is small
|
|
|
|
|
|
|
|
if (dataSize < 0) |
|
|
|
|
|
|
|
dataSize = 0; |
|
|
|
|
|
|
|
vector<unsigned char> vchData; |
|
|
|
|
|
|
|
vchData.resize(dataSize); |
|
|
|
|
|
|
|
uint256 hashIn; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read data and checksum from file
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
filein.read((char *)&vchData[0], dataSize); |
|
|
|
|
|
|
|
filein >> hashIn; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (const std::exception& e) { |
|
|
|
|
|
|
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
filein.fclose(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// verify stored checksum matches input data
|
|
|
|
|
|
|
|
uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); |
|
|
|
|
|
|
|
if (hashIn != hashTmp) |
|
|
|
|
|
|
|
return error("%s: Checksum mismatch, data corrupted", __func__); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned char pchMsgTmp[4]; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// de-serialize file header (network specific magic number) and ..
|
|
|
|
|
|
|
|
ssBanlist >> FLATDATA(pchMsgTmp); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ... verify the network matches ours
|
|
|
|
|
|
|
|
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) |
|
|
|
|
|
|
|
return error("%s: Invalid network magic number", __func__); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// de-serialize address data into one CAddrMan object
|
|
|
|
|
|
|
|
ssBanlist >> banSet; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (const std::exception& e) { |
|
|
|
|
|
|
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DumpBanlist() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int64_t nStart = GetTimeMillis(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CNode::SweepBanned(); //clean unused entires (if bantime has expired)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBanDB bandb; |
|
|
|
|
|
|
|
std::map<CSubNet, int64_t> banmap; |
|
|
|
|
|
|
|
CNode::GetBanned(banmap); |
|
|
|
|
|
|
|
bandb.Write(banmap); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", |
|
|
|
|
|
|
|
banmap.size(), GetTimeMillis() - nStart); |
|
|
|
|
|
|
|
} |