Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2020 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 <netaddress.h>
# 9 : : #include <node/ui_interface.h>
# 10 : : #include <util/system.h>
# 11 : : #include <util/time.h>
# 12 : : #include <util/translation.h>
# 13 : :
# 14 : :
# 15 : : BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
# 16 : : : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
# 17 : 794 : {
# 18 [ + + ]: 794 : if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
# 19 : :
# 20 : 794 : int64_t n_start = GetTimeMillis();
# 21 : 794 : m_is_dirty = false;
# 22 : 794 : banmap_t banmap;
# 23 [ + + ]: 794 : if (m_ban_db.Read(banmap)) {
# 24 : 268 : SetBanned(banmap); // thread save setter
# 25 : 268 : SetBannedSetDirty(false); // no need to write down, just read data
# 26 : 268 : SweepBanned(); // sweep out unused entries
# 27 : :
# 28 [ + - ]: 268 : LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
# 29 : 268 : m_banned.size(), GetTimeMillis() - n_start);
# 30 : 526 : } else {
# 31 : 526 : LogPrintf("Recreating banlist.dat\n");
# 32 : 526 : SetBannedSetDirty(true); // force write
# 33 : 526 : DumpBanlist();
# 34 : 526 : }
# 35 : 794 : }
# 36 : :
# 37 : : BanMan::~BanMan()
# 38 : 794 : {
# 39 : 794 : DumpBanlist();
# 40 : 794 : }
# 41 : :
# 42 : : void BanMan::DumpBanlist()
# 43 : 1372 : {
# 44 : 1372 : SweepBanned(); // clean unused entries (if bantime has expired)
# 45 : :
# 46 [ + + ]: 1372 : if (!BannedSetIsDirty()) return;
# 47 : :
# 48 : 573 : int64_t n_start = GetTimeMillis();
# 49 : :
# 50 : 573 : banmap_t banmap;
# 51 : 573 : GetBanned(banmap);
# 52 [ + - ]: 573 : if (m_ban_db.Write(banmap)) {
# 53 : 573 : SetBannedSetDirty(false);
# 54 : 573 : }
# 55 : :
# 56 [ + - ]: 573 : LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
# 57 : 573 : banmap.size(), GetTimeMillis() - n_start);
# 58 : 573 : }
# 59 : :
# 60 : : void BanMan::ClearBanned()
# 61 : 17 : {
# 62 : 17 : {
# 63 : 17 : LOCK(m_cs_banned);
# 64 : 17 : m_banned.clear();
# 65 : 17 : m_is_dirty = true;
# 66 : 17 : }
# 67 : 17 : DumpBanlist(); //store banlist to disk
# 68 [ + + ]: 17 : if (m_client_interface) m_client_interface->BannedListChanged();
# 69 : 17 : }
# 70 : :
# 71 : : bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
# 72 : 20674 : {
# 73 : 20674 : LOCK(m_cs_banned);
# 74 : 20674 : return m_discouraged.contains(net_addr.GetAddrBytes());
# 75 : 20674 : }
# 76 : :
# 77 : : bool BanMan::IsBanned(const CNetAddr& net_addr)
# 78 : 20668 : {
# 79 : 20668 : auto current_time = GetTime();
# 80 : 20668 : LOCK(m_cs_banned);
# 81 [ + + ]: 20668 : for (const auto& it : m_banned) {
# 82 : 9 : CSubNet sub_net = it.first;
# 83 : 9 : CBanEntry ban_entry = it.second;
# 84 : :
# 85 [ + - ][ + + ]: 9 : if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
# 86 : 7 : return true;
# 87 : 7 : }
# 88 : 9 : }
# 89 : 20668 : return false;
# 90 : 20668 : }
# 91 : :
# 92 : : bool BanMan::IsBanned(const CSubNet& sub_net)
# 93 : 14 : {
# 94 : 14 : auto current_time = GetTime();
# 95 : 14 : LOCK(m_cs_banned);
# 96 : 14 : banmap_t::iterator i = m_banned.find(sub_net);
# 97 [ - + ]: 14 : if (i != m_banned.end()) {
# 98 : 0 : CBanEntry ban_entry = (*i).second;
# 99 [ # # ]: 0 : if (current_time < ban_entry.nBanUntil) {
# 100 : 0 : return true;
# 101 : 0 : }
# 102 : 14 : }
# 103 : 14 : return false;
# 104 : 14 : }
# 105 : :
# 106 : : void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
# 107 : 8 : {
# 108 : 8 : CSubNet sub_net(net_addr);
# 109 : 8 : Ban(sub_net, ban_time_offset, since_unix_epoch);
# 110 : 8 : }
# 111 : :
# 112 : : void BanMan::Discourage(const CNetAddr& net_addr)
# 113 : 8 : {
# 114 : 8 : LOCK(m_cs_banned);
# 115 : 8 : m_discouraged.insert(net_addr.GetAddrBytes());
# 116 : 8 : }
# 117 : :
# 118 : : void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
# 119 : 22 : {
# 120 : 22 : CBanEntry ban_entry(GetTime());
# 121 : :
# 122 : 22 : int64_t normalized_ban_time_offset = ban_time_offset;
# 123 : 22 : bool normalized_since_unix_epoch = since_unix_epoch;
# 124 [ + + ]: 22 : if (ban_time_offset <= 0) {
# 125 : 16 : normalized_ban_time_offset = m_default_ban_time;
# 126 : 16 : normalized_since_unix_epoch = false;
# 127 : 16 : }
# 128 [ + + ]: 22 : ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
# 129 : :
# 130 : 22 : {
# 131 : 22 : LOCK(m_cs_banned);
# 132 [ + - ]: 22 : if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
# 133 : 22 : m_banned[sub_net] = ban_entry;
# 134 : 22 : m_is_dirty = true;
# 135 : 22 : } else
# 136 : 0 : return;
# 137 : 22 : }
# 138 [ + + ]: 22 : if (m_client_interface) m_client_interface->BannedListChanged();
# 139 : :
# 140 : : //store banlist to disk immediately
# 141 : 22 : DumpBanlist();
# 142 : 22 : }
# 143 : :
# 144 : : bool BanMan::Unban(const CNetAddr& net_addr)
# 145 : 5 : {
# 146 : 5 : CSubNet sub_net(net_addr);
# 147 : 5 : return Unban(sub_net);
# 148 : 5 : }
# 149 : :
# 150 : : bool BanMan::Unban(const CSubNet& sub_net)
# 151 : 8 : {
# 152 : 8 : {
# 153 : 8 : LOCK(m_cs_banned);
# 154 [ + + ]: 8 : if (m_banned.erase(sub_net) == 0) return false;
# 155 : 7 : m_is_dirty = true;
# 156 : 7 : }
# 157 [ + + ]: 7 : if (m_client_interface) m_client_interface->BannedListChanged();
# 158 : 7 : DumpBanlist(); //store banlist to disk immediately
# 159 : 7 : return true;
# 160 : 7 : }
# 161 : :
# 162 : : void BanMan::GetBanned(banmap_t& banmap)
# 163 : 607 : {
# 164 : 607 : LOCK(m_cs_banned);
# 165 : : // Sweep the banlist so expired bans are not returned
# 166 : 607 : SweepBanned();
# 167 : 607 : banmap = m_banned; //create a thread safe copy
# 168 : 607 : }
# 169 : :
# 170 : : void BanMan::SetBanned(const banmap_t& banmap)
# 171 : 268 : {
# 172 : 268 : LOCK(m_cs_banned);
# 173 : 268 : m_banned = banmap;
# 174 : 268 : m_is_dirty = true;
# 175 : 268 : }
# 176 : :
# 177 : : void BanMan::SweepBanned()
# 178 : 2247 : {
# 179 : 2247 : int64_t now = GetTime();
# 180 : 2247 : bool notify_ui = false;
# 181 : 2247 : {
# 182 : 2247 : LOCK(m_cs_banned);
# 183 : 2247 : banmap_t::iterator it = m_banned.begin();
# 184 [ + + ]: 2347 : while (it != m_banned.end()) {
# 185 : 100 : CSubNet sub_net = (*it).first;
# 186 : 100 : CBanEntry ban_entry = (*it).second;
# 187 [ - + ][ + + ]: 100 : if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
# 188 : 1 : m_banned.erase(it++);
# 189 : 1 : m_is_dirty = true;
# 190 : 1 : notify_ui = true;
# 191 [ + - ]: 1 : LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString());
# 192 : 1 : } else
# 193 : 99 : ++it;
# 194 : 100 : }
# 195 : 2247 : }
# 196 : : // update UI
# 197 [ + + ][ + - ]: 2247 : if (notify_ui && m_client_interface) {
# 198 : 1 : m_client_interface->BannedListChanged();
# 199 : 1 : }
# 200 : 2247 : }
# 201 : :
# 202 : : bool BanMan::BannedSetIsDirty()
# 203 : 1372 : {
# 204 : 1372 : LOCK(m_cs_banned);
# 205 : 1372 : return m_is_dirty;
# 206 : 1372 : }
# 207 : :
# 208 : : void BanMan::SetBannedSetDirty(bool dirty)
# 209 : 1367 : {
# 210 : 1367 : LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
# 211 : 1367 : m_is_dirty = dirty;
# 212 : 1367 : }
|