@@ -445,11 +445,13 @@ void CNode::PushVersion()
445
445
446
446
std::map<CSubNet, int64_t > CNode::setBanned;
447
447
CCriticalSection CNode::cs_setBanned;
448
+ bool CNode::setBannedIsDirty;
448
449
449
450
void CNode::ClearBanned ()
450
451
{
451
452
LOCK (cs_setBanned);
452
453
setBanned.clear ();
454
+ setBannedIsDirty = true ;
453
455
}
454
456
455
457
bool CNode::IsBanned (CNetAddr ip)
@@ -498,6 +500,8 @@ void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoc
498
500
LOCK (cs_setBanned);
499
501
if (setBanned[subNet] < banTime)
500
502
setBanned[subNet] = banTime;
503
+
504
+ setBannedIsDirty = true ;
501
505
}
502
506
503
507
bool CNode::Unban (const CNetAddr &addr) {
@@ -508,7 +512,10 @@ bool CNode::Unban(const CNetAddr &addr) {
508
512
bool CNode::Unban (const CSubNet &subNet) {
509
513
LOCK (cs_setBanned);
510
514
if (setBanned.erase (subNet))
515
+ {
516
+ setBannedIsDirty = true ;
511
517
return true ;
518
+ }
512
519
return false ;
513
520
}
514
521
@@ -518,6 +525,43 @@ void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap)
518
525
banMap = setBanned; // create a thread safe copy
519
526
}
520
527
528
+ void CNode::SetBanned (const std::map<CSubNet, int64_t > &banMap)
529
+ {
530
+ LOCK (cs_setBanned);
531
+ setBanned = banMap;
532
+ setBannedIsDirty = true ;
533
+ }
534
+
535
+ void CNode::SweepBanned ()
536
+ {
537
+ int64_t now = GetTime ();
538
+
539
+ LOCK (cs_setBanned);
540
+ std::map<CSubNet, int64_t >::iterator it = setBanned.begin ();
541
+ while (it != setBanned.end ())
542
+ {
543
+ if (now > (*it).second )
544
+ {
545
+ setBanned.erase (it++);
546
+ setBannedIsDirty = true ;
547
+ }
548
+ else
549
+ ++it;
550
+ }
551
+ }
552
+
553
+ bool CNode::BannedSetIsDirty ()
554
+ {
555
+ LOCK (cs_setBanned);
556
+ return setBannedIsDirty;
557
+ }
558
+
559
+ void CNode::SetBannedSetDirty (bool dirty)
560
+ {
561
+ LOCK (cs_setBanned); // reuse setBanned lock for the isDirty flag
562
+ setBannedIsDirty = dirty;
563
+ }
564
+
521
565
522
566
std::vector<CSubNet> CNode::vWhitelistedRange;
523
567
CCriticalSection CNode::cs_vWhitelistedRange;
@@ -1212,6 +1256,17 @@ void DumpAddresses()
1212
1256
addrman.size (), GetTimeMillis () - nStart);
1213
1257
}
1214
1258
1259
+ void DumpData ()
1260
+ {
1261
+ DumpAddresses ();
1262
+
1263
+ if (CNode::BannedSetIsDirty ())
1264
+ {
1265
+ DumpBanlist ();
1266
+ CNode::SetBannedSetDirty (false );
1267
+ }
1268
+ }
1269
+
1215
1270
void static ProcessOneShot ()
1216
1271
{
1217
1272
string strDest;
@@ -1650,6 +1705,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
1650
1705
if (!adb.Read (addrman))
1651
1706
LogPrintf (" Invalid or missing peers.dat; recreating\n " );
1652
1707
}
1708
+
1709
+ // try to read stored banlist
1710
+ CBanDB bandb;
1711
+ std::map<CSubNet, int64_t > banmap;
1712
+ if (!bandb.Read (banmap))
1713
+ LogPrintf (" Invalid or missing banlist.dat; recreating\n " );
1714
+
1715
+ CNode::SetBanned (banmap); // thread save setter
1716
+ CNode::SetBannedSetDirty (false ); // no need to write down just read or nonexistent data
1717
+ CNode::SweepBanned (); // sweap out unused entries
1718
+
1653
1719
LogPrintf (" Loaded %i addresses from peers.dat %dms\n " ,
1654
1720
addrman.size (), GetTimeMillis () - nStart);
1655
1721
fAddressesInitialized = true ;
@@ -1690,7 +1756,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
1690
1756
threadGroup.create_thread (boost::bind (&TraceThread<void (*)()>, " msghand" , &ThreadMessageHandler));
1691
1757
1692
1758
// Dump network addresses
1693
- scheduler.scheduleEvery (&DumpAddresses , DUMP_ADDRESSES_INTERVAL);
1759
+ scheduler.scheduleEvery (&DumpData , DUMP_ADDRESSES_INTERVAL);
1694
1760
}
1695
1761
1696
1762
bool StopNode ()
@@ -1703,7 +1769,7 @@ bool StopNode()
1703
1769
1704
1770
if (fAddressesInitialized )
1705
1771
{
1706
- DumpAddresses ();
1772
+ DumpData ();
1707
1773
fAddressesInitialized = false ;
1708
1774
}
1709
1775
@@ -2107,3 +2173,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
2107
2173
2108
2174
LEAVE_CRITICAL_SECTION (cs_vSend);
2109
2175
}
2176
+
2177
+ //
2178
+ // CBanDB
2179
+ //
2180
+
2181
+ CBanDB::CBanDB ()
2182
+ {
2183
+ pathBanlist = GetDataDir () / " banlist.dat" ;
2184
+ }
2185
+
2186
+ bool CBanDB::Write (const std::map<CSubNet, int64_t >& banSet)
2187
+ {
2188
+ // Generate random temporary filename
2189
+ unsigned short randv = 0 ;
2190
+ GetRandBytes ((unsigned char *)&randv, sizeof (randv));
2191
+ std::string tmpfn = strprintf (" banlist.dat.%04x" , randv);
2192
+
2193
+ // serialize banlist, checksum data up to that point, then append csum
2194
+ CDataStream ssBanlist (SER_DISK, CLIENT_VERSION);
2195
+ ssBanlist << FLATDATA (Params ().MessageStart ());
2196
+ ssBanlist << banSet;
2197
+ uint256 hash = Hash (ssBanlist.begin (), ssBanlist.end ());
2198
+ ssBanlist << hash;
2199
+
2200
+ // open temp output file, and associate with CAutoFile
2201
+ boost::filesystem::path pathTmp = GetDataDir () / tmpfn;
2202
+ FILE *file = fopen (pathTmp.string ().c_str (), " wb" );
2203
+ CAutoFile fileout (file, SER_DISK, CLIENT_VERSION);
2204
+ if (fileout.IsNull ())
2205
+ return error (" %s: Failed to open file %s" , __func__, pathTmp.string ());
2206
+
2207
+ // Write and commit header, data
2208
+ try {
2209
+ fileout << ssBanlist;
2210
+ }
2211
+ catch (const std::exception& e) {
2212
+ return error (" %s: Serialize or I/O error - %s" , __func__, e.what ());
2213
+ }
2214
+ FileCommit (fileout.Get ());
2215
+ fileout.fclose ();
2216
+
2217
+ // replace existing banlist.dat, if any, with new banlist.dat.XXXX
2218
+ if (!RenameOver (pathTmp, pathBanlist))
2219
+ return error (" %s: Rename-into-place failed" , __func__);
2220
+
2221
+ return true ;
2222
+ }
2223
+
2224
+ bool CBanDB::Read (std::map<CSubNet, int64_t >& banSet)
2225
+ {
2226
+ // open input file, and associate with CAutoFile
2227
+ FILE *file = fopen (pathBanlist.string ().c_str (), " rb" );
2228
+ CAutoFile filein (file, SER_DISK, CLIENT_VERSION);
2229
+ if (filein.IsNull ())
2230
+ return error (" %s: Failed to open file %s" , __func__, pathBanlist.string ());
2231
+
2232
+ // use file size to size memory buffer
2233
+ int fileSize = boost::filesystem::file_size (pathBanlist);
2234
+ int dataSize = fileSize - sizeof (uint256);
2235
+ // Don't try to resize to a negative number if file is small
2236
+ if (dataSize < 0 )
2237
+ dataSize = 0 ;
2238
+ vector<unsigned char > vchData;
2239
+ vchData.resize (dataSize);
2240
+ uint256 hashIn;
2241
+
2242
+ // read data and checksum from file
2243
+ try {
2244
+ filein.read ((char *)&vchData[0 ], dataSize);
2245
+ filein >> hashIn;
2246
+ }
2247
+ catch (const std::exception& e) {
2248
+ return error (" %s: Deserialize or I/O error - %s" , __func__, e.what ());
2249
+ }
2250
+ filein.fclose ();
2251
+
2252
+ CDataStream ssBanlist (vchData, SER_DISK, CLIENT_VERSION);
2253
+
2254
+ // verify stored checksum matches input data
2255
+ uint256 hashTmp = Hash (ssBanlist.begin (), ssBanlist.end ());
2256
+ if (hashIn != hashTmp)
2257
+ return error (" %s: Checksum mismatch, data corrupted" , __func__);
2258
+
2259
+ unsigned char pchMsgTmp[4 ];
2260
+ try {
2261
+ // de-serialize file header (network specific magic number) and ..
2262
+ ssBanlist >> FLATDATA (pchMsgTmp);
2263
+
2264
+ // ... verify the network matches ours
2265
+ if (memcmp (pchMsgTmp, Params ().MessageStart (), sizeof (pchMsgTmp)))
2266
+ return error (" %s: Invalid network magic number" , __func__);
2267
+
2268
+ // de-serialize address data into one CAddrMan object
2269
+ ssBanlist >> banSet;
2270
+ }
2271
+ catch (const std::exception& e) {
2272
+ return error (" %s: Deserialize or I/O error - %s" , __func__, e.what ());
2273
+ }
2274
+
2275
+ return true ;
2276
+ }
2277
+
2278
+ void DumpBanlist ()
2279
+ {
2280
+ int64_t nStart = GetTimeMillis ();
2281
+
2282
+ CNode::SweepBanned (); // clean unused entires (if bantime has expired)
2283
+
2284
+ CBanDB bandb;
2285
+ std::map<CSubNet, int64_t > banmap;
2286
+ CNode::GetBanned (banmap);
2287
+ bandb.Write (banmap);
2288
+
2289
+ LogPrint (" net" , " Flushed %d banned node ips/subnets to banlist.dat %dms\n " ,
2290
+ banmap.size (), GetTimeMillis () - nStart);
2291
+ }
0 commit comments