/Users/eugenesiegel/btc/bitcoin/src/banman.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-2010 Satoshi Nakamoto | 
| 2 |  | // Copyright (c) 2009-2022 The Bitcoin Core developers | 
| 3 |  | // Distributed under the MIT software license, see the accompanying | 
| 4 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 5 |  |  | 
| 6 |  | #include <banman.h> | 
| 7 |  |  | 
| 8 |  | #include <common/system.h> | 
| 9 |  | #include <logging.h> | 
| 10 |  | #include <netaddress.h> | 
| 11 |  | #include <node/interface_ui.h> | 
| 12 |  | #include <sync.h> | 
| 13 |  | #include <util/time.h> | 
| 14 |  | #include <util/translation.h> | 
| 15 |  |  | 
| 16 |  |  | 
| 17 |  | BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) | 
| 18 | 51.2k |     : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time) | 
| 19 | 51.2k | { | 
| 20 | 51.2k |     LoadBanlist(); | 
| 21 | 51.2k |     DumpBanlist(); | 
| 22 | 51.2k | } | 
| 23 |  |  | 
| 24 |  | BanMan::~BanMan() | 
| 25 | 51.2k | { | 
| 26 | 51.2k |     DumpBanlist(); | 
| 27 | 51.2k | } | 
| 28 |  |  | 
| 29 |  | void BanMan::LoadBanlist() | 
| 30 | 51.2k | { | 
| 31 | 51.2k |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 32 |  |  | 
| 33 | 51.2k |     if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…"))0; | 
| 34 |  |  | 
| 35 | 51.2k |     const auto start{SteadyClock::now()}; | 
| 36 | 51.2k |     if (m_ban_db.Read(m_banned)) { | 
| 37 | 51.2k |         SweepBanned(); // sweep out unused entries | 
| 38 |  |  | 
| 39 | 51.2k |         LogDebug(BCLog::NET, "Loaded %d banned node addresses/subnets  %dms\n", m_banned.size(), | Line | Count | Source |  | 381 | 51.2k | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 51.2k |     do {                                                              \ |  | 374 | 51.2k |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 51.2k |     } while (0) | 
 | 
 | 
| 40 | 51.2k |                  Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); | 
| 41 | 51.2k |     } else { | 
| 42 | 0 |         LogInfo("Recreating the banlist database");| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 43 | 0 |         m_banned = {}; | 
| 44 | 0 |         m_is_dirty = true; | 
| 45 | 0 |     } | 
| 46 | 51.2k | } | 
| 47 |  |  | 
| 48 |  | void BanMan::DumpBanlist() | 
| 49 | 102k | { | 
| 50 | 102k |     static Mutex dump_mutex; | 
| 51 | 102k |     LOCK(dump_mutex); | Line | Count | Source |  | 259 | 102k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 102k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 102k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 102k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 52 |  |  | 
| 53 | 102k |     banmap_t banmap; | 
| 54 | 102k |     { | 
| 55 | 102k |         LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 102k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 102k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 102k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 102k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 56 | 102k |         SweepBanned(); | 
| 57 | 102k |         if (!m_is_dirty) return; | 
| 58 | 0 |         banmap = m_banned; | 
| 59 | 0 |         m_is_dirty = false; | 
| 60 | 0 |     } | 
| 61 |  |  | 
| 62 | 0 |     const auto start{SteadyClock::now()}; | 
| 63 | 0 |     if (!m_ban_db.Write(banmap)) { | 
| 64 | 0 |         LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 65 | 0 |         m_is_dirty = true; | 
| 66 | 0 |     } | 
| 67 |  | 
 | 
| 68 | 0 |     LogDebug(BCLog::NET, "Flushed %d banned node addresses/subnets to disk  %dms\n", banmap.size(), | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 69 | 0 |              Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); | 
| 70 | 0 | } | 
| 71 |  |  | 
| 72 |  | void BanMan::ClearBanned() | 
| 73 | 0 | { | 
| 74 | 0 |     { | 
| 75 | 0 |         LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 76 | 0 |         m_banned.clear(); | 
| 77 | 0 |         m_is_dirty = true; | 
| 78 | 0 |     } | 
| 79 | 0 |     DumpBanlist(); //store banlist to disk | 
| 80 | 0 |     if (m_client_interface) m_client_interface->BannedListChanged(); | 
| 81 | 0 | } | 
| 82 |  |  | 
| 83 |  | bool BanMan::IsDiscouraged(const CNetAddr& net_addr) | 
| 84 | 0 | { | 
| 85 | 0 |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 86 | 0 |     return m_discouraged.contains(net_addr.GetAddrBytes()); | 
| 87 | 0 | } | 
| 88 |  |  | 
| 89 |  | bool BanMan::IsBanned(const CNetAddr& net_addr) | 
| 90 | 0 | { | 
| 91 | 0 |     auto current_time = GetTime(); | 
| 92 | 0 |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 93 | 0 |     for (const auto& it : m_banned) { | 
| 94 | 0 |         CSubNet sub_net = it.first; | 
| 95 | 0 |         CBanEntry ban_entry = it.second; | 
| 96 |  | 
 | 
| 97 | 0 |         if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) { | 
| 98 | 0 |             return true; | 
| 99 | 0 |         } | 
| 100 | 0 |     } | 
| 101 | 0 |     return false; | 
| 102 | 0 | } | 
| 103 |  |  | 
| 104 |  | bool BanMan::IsBanned(const CSubNet& sub_net) | 
| 105 | 0 | { | 
| 106 | 0 |     auto current_time = GetTime(); | 
| 107 | 0 |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 108 | 0 |     banmap_t::iterator i = m_banned.find(sub_net); | 
| 109 | 0 |     if (i != m_banned.end()) { | 
| 110 | 0 |         CBanEntry ban_entry = (*i).second; | 
| 111 | 0 |         if (current_time < ban_entry.nBanUntil) { | 
| 112 | 0 |             return true; | 
| 113 | 0 |         } | 
| 114 | 0 |     } | 
| 115 | 0 |     return false; | 
| 116 | 0 | } | 
| 117 |  |  | 
| 118 |  | void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch) | 
| 119 | 0 | { | 
| 120 | 0 |     CSubNet sub_net(net_addr); | 
| 121 | 0 |     Ban(sub_net, ban_time_offset, since_unix_epoch); | 
| 122 | 0 | } | 
| 123 |  |  | 
| 124 |  | void BanMan::Discourage(const CNetAddr& net_addr) | 
| 125 | 224k | { | 
| 126 | 224k |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 224k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 224k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 224k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 224k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 127 | 224k |     m_discouraged.insert(net_addr.GetAddrBytes()); | 
| 128 | 224k | } | 
| 129 |  |  | 
| 130 |  | void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch) | 
| 131 | 0 | { | 
| 132 | 0 |     CBanEntry ban_entry(GetTime()); | 
| 133 |  | 
 | 
| 134 | 0 |     int64_t normalized_ban_time_offset = ban_time_offset; | 
| 135 | 0 |     bool normalized_since_unix_epoch = since_unix_epoch; | 
| 136 | 0 |     if (ban_time_offset <= 0) { | 
| 137 | 0 |         normalized_ban_time_offset = m_default_ban_time; | 
| 138 | 0 |         normalized_since_unix_epoch = false; | 
| 139 | 0 |     } | 
| 140 | 0 |     ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset; | 
| 141 |  | 
 | 
| 142 | 0 |     { | 
| 143 | 0 |         LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 144 | 0 |         if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) { | 
| 145 | 0 |             m_banned[sub_net] = ban_entry; | 
| 146 | 0 |             m_is_dirty = true; | 
| 147 | 0 |         } else | 
| 148 | 0 |             return; | 
| 149 | 0 |     } | 
| 150 | 0 |     if (m_client_interface) m_client_interface->BannedListChanged(); | 
| 151 |  |  | 
| 152 |  |     //store banlist to disk immediately | 
| 153 | 0 |     DumpBanlist(); | 
| 154 | 0 | } | 
| 155 |  |  | 
| 156 |  | bool BanMan::Unban(const CNetAddr& net_addr) | 
| 157 | 0 | { | 
| 158 | 0 |     CSubNet sub_net(net_addr); | 
| 159 | 0 |     return Unban(sub_net); | 
| 160 | 0 | } | 
| 161 |  |  | 
| 162 |  | bool BanMan::Unban(const CSubNet& sub_net) | 
| 163 | 0 | { | 
| 164 | 0 |     { | 
| 165 | 0 |         LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 166 | 0 |         if (m_banned.erase(sub_net) == 0) return false; | 
| 167 | 0 |         m_is_dirty = true; | 
| 168 | 0 |     } | 
| 169 | 0 |     if (m_client_interface) m_client_interface->BannedListChanged(); | 
| 170 | 0 |     DumpBanlist(); //store banlist to disk immediately | 
| 171 | 0 |     return true; | 
| 172 | 0 | } | 
| 173 |  |  | 
| 174 |  | void BanMan::GetBanned(banmap_t& banmap) | 
| 175 | 0 | { | 
| 176 | 0 |     LOCK(m_banned_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 177 |  |     // Sweep the banlist so expired bans are not returned | 
| 178 | 0 |     SweepBanned(); | 
| 179 | 0 |     banmap = m_banned; //create a thread safe copy | 
| 180 | 0 | } | 
| 181 |  |  | 
| 182 |  | void BanMan::SweepBanned() | 
| 183 | 153k | { | 
| 184 | 153k |     AssertLockHeld(m_banned_mutex); | Line | Count | Source |  | 137 | 153k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) | 
 | 
| 185 |  |  | 
| 186 | 153k |     int64_t now = GetTime(); | 
| 187 | 153k |     bool notify_ui = false; | 
| 188 | 153k |     banmap_t::iterator it = m_banned.begin(); | 
| 189 | 153k |     while (it != m_banned.end()) { | 
| 190 | 0 |         CSubNet sub_net = (*it).first; | 
| 191 | 0 |         CBanEntry ban_entry = (*it).second; | 
| 192 | 0 |         if (!sub_net.IsValid() || now > ban_entry.nBanUntil) { | 
| 193 | 0 |             m_banned.erase(it++); | 
| 194 | 0 |             m_is_dirty = true; | 
| 195 | 0 |             notify_ui = true; | 
| 196 | 0 |             LogDebug(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString()); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 197 | 0 |         } else { | 
| 198 | 0 |             ++it; | 
| 199 | 0 |         } | 
| 200 | 0 |     } | 
| 201 |  |  | 
| 202 |  |     // update UI | 
| 203 | 153k |     if (notify_ui && m_client_interface0) { | 
| 204 | 0 |         m_client_interface->BannedListChanged(); | 
| 205 | 0 |     } | 
| 206 | 153k | } |