Branch data Line data Source code
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 : 4327 : BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) 18 [ + - ]: 4327 : : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time) 19 : : { 20 [ + - ]: 4327 : LoadBanlist(); 21 [ + - ]: 4327 : DumpBanlist(); 22 : 4327 : } 23 : : 24 : 4345 : BanMan::~BanMan() 25 : : { 26 [ + - ]: 4345 : DumpBanlist(); 27 : 4345 : } 28 : : 29 : 4327 : void BanMan::LoadBanlist() 30 : : { 31 : 4327 : LOCK(m_banned_mutex); 32 : : 33 [ + - # # : 4327 : if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated); # # ] 34 : : 35 : 4327 : const auto start{SteadyClock::now()}; 36 [ + - + + ]: 4327 : if (m_ban_db.Read(m_banned)) { 37 [ + - ]: 1928 : SweepBanned(); // sweep out unused entries 38 : : 39 [ + - + - : 1928 : LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(), # # # # # # # # # # ] 40 : : Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); 41 : 1928 : } else { 42 [ + - + - : 2399 : LogPrintf("Recreating the banlist database\n"); + - ] 43 [ + - ]: 2399 : m_banned = {}; 44 : 2399 : m_is_dirty = true; 45 : : } 46 : 4327 : } 47 : : 48 : 33550 : void BanMan::DumpBanlist() 49 : : { 50 [ + + - + ]: 33550 : static Mutex dump_mutex; 51 : 33550 : LOCK(dump_mutex); 52 : : 53 : 33550 : banmap_t banmap; 54 : : { 55 [ + - + - ]: 33550 : LOCK(m_banned_mutex); 56 [ + - ]: 33550 : SweepBanned(); 57 [ + + ]: 33550 : if (!m_is_dirty) return; 58 [ + - ]: 25048 : banmap = m_banned; 59 : 25048 : m_is_dirty = false; 60 [ + + ]: 33550 : } 61 : : 62 : 25048 : const auto start{SteadyClock::now()}; 63 [ + - + + ]: 25048 : if (!m_ban_db.Write(banmap)) { 64 [ + - + - ]: 4705 : LOCK(m_banned_mutex); 65 : 4705 : m_is_dirty = true; 66 : 4705 : } 67 : : 68 [ + - + + : 25048 : LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(), + - + - + - + - + - ] 69 : : Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); 70 [ - + ]: 33550 : } 71 : : 72 : 3049 : void BanMan::ClearBanned() 73 : : { 74 : 1 : { 75 : 3049 : LOCK(m_banned_mutex); 76 : 3049 : m_banned.clear(); 77 : 3049 : m_is_dirty = true; 78 : 3049 : } 79 : 3049 : DumpBanlist(); //store banlist to disk 80 [ - + ]: 3049 : if (m_client_interface) m_client_interface->BannedListChanged(); 81 : 3049 : } 82 : : 83 : 147417 : bool BanMan::IsDiscouraged(const CNetAddr& net_addr) 84 : : { 85 : 147417 : LOCK(m_banned_mutex); 86 [ + - + - : 147417 : return m_discouraged.contains(net_addr.GetAddrBytes()); + - ] 87 : 147417 : } 88 : : 89 : 158667 : bool BanMan::IsBanned(const CNetAddr& net_addr) 90 : : { 91 : 154340 : auto current_time = GetTime(); 92 : 154340 : LOCK(m_banned_mutex); 93 [ - + + + : 212210 : for (const auto& it : m_banned) { + + ] 94 [ + - ]: 53543 : CSubNet sub_net = it.first; 95 : 53543 : CBanEntry ban_entry = it.second; 96 : : 97 [ + + + - : 53543 : if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) { + + ] 98 : 1688 : return true; 99 : : } 100 [ + + + + ]: 53543 : } 101 : 152652 : return false; 102 : 154340 : } 103 : : 104 : 2829 : bool BanMan::IsBanned(const CSubNet& sub_net) 105 : : { 106 : 2829 : auto current_time = GetTime(); 107 : 2829 : LOCK(m_banned_mutex); 108 [ + - ]: 2829 : banmap_t::iterator i = m_banned.find(sub_net); 109 [ + + ]: 2829 : if (i != m_banned.end()) { 110 : 959 : CBanEntry ban_entry = (*i).second; 111 [ + + ]: 959 : if (current_time < ban_entry.nBanUntil) { 112 : 530 : return true; 113 : : } 114 [ + + ]: 959 : } 115 : 2299 : return false; 116 : 2829 : } 117 : : 118 : 8227 : void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch) 119 : : { 120 : 8227 : CSubNet sub_net(net_addr); 121 [ + - ]: 8227 : Ban(sub_net, ban_time_offset, since_unix_epoch); 122 : 8227 : } 123 : : 124 : 7423 : void BanMan::Discourage(const CNetAddr& net_addr) 125 : : { 126 : 7423 : LOCK(m_banned_mutex); 127 [ + - + - : 7423 : m_discouraged.insert(net_addr.GetAddrBytes()); + - ] 128 : 7423 : } 129 : : 130 : 27030 : void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch) 131 : : { 132 : 27030 : CBanEntry ban_entry(GetTime()); 133 : : 134 : 27030 : int64_t normalized_ban_time_offset = ban_time_offset; 135 : 27030 : bool normalized_since_unix_epoch = since_unix_epoch; 136 [ + + ]: 27030 : if (ban_time_offset <= 0) { 137 : 26886 : normalized_ban_time_offset = m_default_ban_time; 138 : 26886 : normalized_since_unix_epoch = false; 139 : 26886 : } 140 [ + + ]: 27030 : ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset; 141 : : 142 : : { 143 : 27030 : LOCK(m_banned_mutex); 144 [ + - + + ]: 27030 : if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) { 145 [ + - ]: 16314 : m_banned[sub_net] = ban_entry; 146 : 16314 : m_is_dirty = true; 147 : 16314 : } else 148 : 10716 : return; 149 [ + + ]: 27030 : } 150 [ + - ]: 16314 : if (m_client_interface) m_client_interface->BannedListChanged(); 151 : : 152 : : //store banlist to disk immediately 153 : 16314 : DumpBanlist(); 154 [ - + ]: 27030 : } 155 : : 156 : 6981 : bool BanMan::Unban(const CNetAddr& net_addr) 157 : : { 158 : 6981 : CSubNet sub_net(net_addr); 159 [ + - ]: 6981 : return Unban(sub_net); 160 : 6981 : } 161 : : 162 : 7930 : bool BanMan::Unban(const CSubNet& sub_net) 163 : : { 164 : : { 165 : 7930 : LOCK(m_banned_mutex); 166 [ + - + + ]: 7930 : if (m_banned.erase(sub_net) == 0) return false; 167 : 697 : m_is_dirty = true; 168 [ - + + ]: 7930 : } 169 [ - + ]: 697 : if (m_client_interface) m_client_interface->BannedListChanged(); 170 : 697 : DumpBanlist(); //store banlist to disk immediately 171 : 697 : return true; 172 : 7930 : } 173 : : 174 : 17310 : void BanMan::GetBanned(banmap_t& banmap) 175 : : { 176 : 17310 : LOCK(m_banned_mutex); 177 : : // Sweep the banlist so expired bans are not returned 178 [ + - ]: 17310 : SweepBanned(); 179 [ + - ]: 17310 : banmap = m_banned; //create a thread safe copy 180 : 17310 : } 181 : : 182 : 52788 : void BanMan::SweepBanned() 183 : : { 184 : 52788 : AssertLockHeld(m_banned_mutex); 185 : : 186 : 52788 : int64_t now = GetTime(); 187 : 52788 : bool notify_ui = false; 188 : 52788 : banmap_t::iterator it = m_banned.begin(); 189 [ + + ]: 1118637 : while (it != m_banned.end()) { 190 : 1065849 : CSubNet sub_net = (*it).first; 191 : 1065849 : CBanEntry ban_entry = (*it).second; 192 [ + - + + : 1065849 : if (!sub_net.IsValid() || now > ban_entry.nBanUntil) { + + ] 193 [ + - ]: 7067 : m_banned.erase(it++); 194 : 7067 : m_is_dirty = true; 195 : 7067 : notify_ui = true; 196 [ + - + - : 7067 : LogPrint(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString()); # # # # # # # # ] 197 : 7067 : } else { 198 : 1058782 : ++it; 199 : : } 200 : 1065849 : } 201 : : 202 : : // update UI 203 [ + + + - ]: 52788 : if (notify_ui && m_client_interface) { 204 : 0 : m_client_interface->BannedListChanged(); 205 : 0 : } 206 : 52788 : }