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