@ -443,13 +443,15 @@ void CNode::PushVersion()
@@ -443,13 +443,15 @@ void CNode::PushVersion()
std : : map < CSubNet , int64_t > CNode : : setBanned ;
banmap_t CNode : : setBanned ;
CCriticalSection CNode : : cs_setBanned ;
bool CNode : : setBannedIsDirty ;
void CNode : : ClearBanned ( )
{
LOCK ( cs_setBanned ) ;
setBanned . clear ( ) ;
setBannedIsDirty = true ;
}
bool CNode : : IsBanned ( CNetAddr ip )
@ -457,12 +459,12 @@ bool CNode::IsBanned(CNetAddr ip)
@@ -457,12 +459,12 @@ bool CNode::IsBanned(CNetAddr ip)
bool fResult = false ;
{
LOCK ( cs_setBanned ) ;
for ( std : : map < CSubNet , int64_t > : : iterator it = setBanned . begin ( ) ; it ! = setBanned . end ( ) ; it + + )
for ( banmap_t : : iterator it = setBanned . begin ( ) ; it ! = setBanned . end ( ) ; it + + )
{
CSubNet subNet = ( * it ) . first ;
int64_t t = ( * it ) . second ;
CBanEntry banEntry = ( * it ) . second ;
if ( subNet . Match ( ip ) & & GetTime ( ) < t )
if ( subNet . Match ( ip ) & & GetTime ( ) < banEn try . nBanUntil )
fResult = true ;
}
}
@ -474,50 +476,99 @@ bool CNode::IsBanned(CSubNet subnet)
@@ -474,50 +476,99 @@ bool CNode::IsBanned(CSubNet subnet)
bool fResult = false ;
{
LOCK ( cs_setBanned ) ;
std : : map < CSubNet , int64_t > : : iterator i = setBanned . find ( subnet ) ;
banmap_t : : iterator i = setBanned . find ( subnet ) ;
if ( i ! = setBanned . end ( ) )
{
int64_t t = ( * i ) . second ;
if ( GetTime ( ) < t )
CBanEntry banEntry = ( * i ) . second ;
if ( GetTime ( ) < banEn try . nBanUntil )
fResult = true ;
}
}
return fResult ;
}
void CNode : : Ban ( const CNetAddr & addr , int64_t bantimeoffset , bool sinceUnixEpoch ) {
CSubNet subNet ( addr . ToString ( ) + ( addr . IsIPv4 ( ) ? " /32 " : " /128 " ) ) ;
Ban ( subNet , bantimeoffset , sinceUnixEpoch ) ;
void CNode : : Ban ( const CNetAddr & addr , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
CSubNet subNet ( addr ) ;
Ban ( subNet , banReason , ban timeoffset , sinceUnixEpoch ) ;
}
void CNode : : Ban ( const CSubNet & subNet , int64_t bantimeoffset , bool sinceUnixEpoch ) {
int64_t banTime = GetTime ( ) + GetArg ( " -bantime " , 60 * 60 * 24 ) ; // Default 24-hour ban
if ( bantimeoffset > 0 )
banTime = ( sinceUnixEpoch ? 0 : GetTime ( ) ) + bantimeoffset ;
void CNode : : Ban ( const CSubNet & subNet , const BanReason & banReason , int64_t bantimeoffset , bool sinceUnixEpoch ) {
CBanEntry banEntry ( GetTime ( ) ) ;
banEntry . banReason = banReason ;
if ( bantimeoffset < = 0 )
{
bantimeoffset = GetArg ( " -bantime " , 60 * 60 * 24 ) ; // Default 24-hour ban
sinceUnixEpoch = false ;
}
banEntry . nBanUntil = ( sinceUnixEpoch ? 0 : GetTime ( ) ) + bantimeoffset ;
LOCK ( cs_setBanned ) ;
if ( setBanned [ subNet ] < banTime )
setBanned [ subNet ] = banTime ;
if ( setBanned [ subNet ] . nBanUntil < banEntry . nBanUntil )
setBanned [ subNet ] = banEntry ;
setBannedIsDirty = true ;
}
bool CNode : : Unban ( const CNetAddr & addr ) {
CSubNet subNet ( addr . ToString ( ) + ( addr . IsIPv4 ( ) ? " /32 " : " /128 " ) ) ;
CSubNet subNet ( addr ) ;
return Unban ( subNet ) ;
}
bool CNode : : Unban ( const CSubNet & subNet ) {
LOCK ( cs_setBanned ) ;
if ( setBanned . erase ( subNet ) )
{
setBannedIsDirty = true ;
return true ;
}
return false ;
}
void CNode : : GetBanned ( std : : map < CSubNet , int64_t > & banMap )
void CNode : : GetBanned ( banmap_t & banMap )
{
LOCK ( cs_setBanned ) ;
banMap = setBanned ; //create a thread safe copy
}
void CNode : : SetBanned ( const banmap_t & banMap )
{
LOCK ( cs_setBanned ) ;
setBanned = banMap ;
setBannedIsDirty = true ;
}
void CNode : : SweepBanned ( )
{
int64_t now = GetTime ( ) ;
LOCK ( cs_setBanned ) ;
banmap_t : : iterator it = setBanned . begin ( ) ;
while ( it ! = setBanned . end ( ) )
{
CBanEntry banEntry = ( * it ) . second ;
if ( now > banEntry . nBanUntil )
{
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 ;
CCriticalSection CNode : : cs_vWhitelistedRange ;
@ -1212,6 +1263,17 @@ void DumpAddresses()
@@ -1212,6 +1263,17 @@ void DumpAddresses()
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
}
void DumpData ( )
{
DumpAddresses ( ) ;
if ( CNode : : BannedSetIsDirty ( ) )
{
DumpBanlist ( ) ;
CNode : : SetBannedSetDirty ( false ) ;
}
}
void static ProcessOneShot ( )
{
string strDest ;
@ -1650,6 +1712,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
@@ -1650,6 +1712,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if ( ! adb . Read ( addrman ) )
LogPrintf ( " Invalid or missing peers.dat; recreating \n " ) ;
}
//try to read stored banlist
CBanDB bandb ;
banmap_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 " ,
addrman . size ( ) , GetTimeMillis ( ) - nStart ) ;
fAddressesInitialized = true ;
@ -1690,7 +1763,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
@@ -1690,7 +1763,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup . create_thread ( boost : : bind ( & TraceThread < void ( * ) ( ) > , " msghand " , & ThreadMessageHandler ) ) ;
// Dump network addresses
scheduler . scheduleEvery ( & DumpAddresses , DUMP_ADDRESSES_INTERVAL ) ;
scheduler . scheduleEvery ( & DumpData , DUMP_ADDRESSES_INTERVAL ) ;
}
bool StopNode ( )
@ -1703,7 +1776,7 @@ bool StopNode()
@@ -1703,7 +1776,7 @@ bool StopNode()
if ( fAddressesInitialized )
{
DumpAddresses ( ) ;
DumpData ( ) ;
fAddressesInitialized = false ;
}
@ -1907,11 +1980,11 @@ bool CAddrDB::Read(CAddrMan& addr)
@@ -1907,11 +1980,11 @@ bool CAddrDB::Read(CAddrMan& addr)
return error ( " %s: Failed to open file %s " , __func__ , pathAddr . string ( ) ) ;
// use file size to size memory buffer
int fileSize = boost : : filesystem : : file_size ( pathAddr ) ;
int dataSize = fileSize - sizeof ( uint256 ) ;
u int64_ t fileSize = boost : : filesystem : : file_size ( pathAddr ) ;
u int64_ t dataSize = 0 ;
// Don't try to resize to a negative number if file is small
if ( dataSize < 0 )
dataSize = 0 ;
if ( fileSize > = sizeof ( uint256 ) )
dataSize = fileSize - sizeof ( uint256 ) ;
vector < unsigned char > vchData ;
vchData . resize ( dataSize ) ;
uint256 hashIn ;
@ -2107,3 +2180,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
@@ -2107,3 +2180,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
LEAVE_CRITICAL_SECTION ( cs_vSend ) ;
}
//
// CBanDB
//
CBanDB : : CBanDB ( )
{
pathBanlist = GetDataDir ( ) / " banlist.dat " ;
}
bool CBanDB : : Write ( const banmap_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 ( banmap_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
uint64_t fileSize = boost : : filesystem : : file_size ( pathBanlist ) ;
uint64_t dataSize = 0 ;
// Don't try to resize to a negative number if file is small
if ( fileSize > = sizeof ( uint256 ) )
dataSize = fileSize - sizeof ( uint256 ) ;
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 ;
banmap_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 ) ;
}