diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2019-01-21 18:45:59 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2019-01-21 18:58:52 +0100 |
commit | 5baa9092c4b8e5098b5258998f7e189ccb560495 (patch) | |
tree | 4951805955d8e368cc1567cf66ce0e66f046dcd7 /src/banman.cpp | |
parent | 0f1576ab32c478efc39a147960eda58b7cfecb47 (diff) | |
parent | 18185b57c32d0a43afeca4c125b9352c692923e9 (diff) | |
download | bitcoin-5baa9092c4b8e5098b5258998f7e189ccb560495.tar.xz |
Merge #14605: Return of the Banman
18185b57c32d0a43afeca4c125b9352c692923e9 scripted-diff: batch-recase BanMan variables (Carl Dong)
c2e04d37f3841d109c1fe60693f9622e2836cc29 banman: Add, use CBanEntry ctor that takes ban reason (Carl Dong)
1ffa4ce27d4ea6c1067d8984455df97994c7713e banman: reformulate nBanUtil calculation (Carl Dong)
daae598feb034f2f56e0b00ecfb4854d693d3641 banman: add thread annotations and mark members const where possible (Cory Fields)
84fc3fbd0304a7d6e660bf783c84bed2dd415141 scripted-diff: batch-rename BanMan members (Cory Fields)
af3503d903b1a608cd212e2d74b274103199078c net: move BanMan to its own files (Cory Fields)
d0469b2e9386a7a4b268cb9725347e7517acace6 banman: pass in default ban time as a parameter (Cory Fields)
2e56702ecedd83c4b7cb8de9de5c437c8c08e645 banman: pass the banfile path in (Cory Fields)
4c0d961eb0d7825a1e6f8389d7f5545114ee18c6 banman: create and split out banman (Cory Fields)
83c1ea2e5e66b8a83072e3d5ad6a4ced406eb1ba net: split up addresses/ban dumps in preparation for moving them (Cory Fields)
136bd7926c72659dd277a7b795ea17f72e523338 tests: remove member connman/peerLogic in TestingSetup (Cory Fields)
7cc2b9f6786f9bc33853220551eed33ca6b7b7b2 net: Break disconnecting out of Ban() (Cory Fields)
Pull request description:
**Old English à la Beowulf**
```
Banman wæs bréme --blaéd wíde sprang--
Connmanes eafera Coreum in.
aéglaéca léodum forstandan
Swá bealdode bearn Connmanes
guma gúðum cúð gódum daédum·
dréah æfter dóme· nealles druncne slóg
```
**Modern English Translation**
```
Banman was famed --his renown spread wide--
Conman's hier, in Core-land.
against the evil creature defend the people
Thus he was bold, the son of Connman
man famed in war, for good deeds;
he led his life for glory, never, having drunk, slew
```
--
With @theuni's blessing, here is Banman, rebased. Original PR: https://github.com/bitcoin/bitcoin/pull/11457
--
Followup PRs:
1. Give `CNode` a `Disconnect` method ([source](https://github.com/bitcoin/bitcoin/pull/14605#discussion_r248065847))
2. Add a comment to `std::atomic_bool fDisconnect` in `net.h` that setting this to true will cause the node to be disconnected the next time `DisconnectNodes()` runs ([source](https://github.com/bitcoin/bitcoin/pull/14605#discussion_r248384309))
Tree-SHA512: 9c207edbf577415c22c9811113e393322d936a843d4ff265186728152a67c057779ac4d4f27b895de9729f7a53e870f828b9ebc8bcdab757520c2aebe1e9be35
Diffstat (limited to 'src/banman.cpp')
-rw-r--r-- | src/banman.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/banman.cpp b/src/banman.cpp new file mode 100644 index 0000000000..9933c829c5 --- /dev/null +++ b/src/banman.cpp @@ -0,0 +1,197 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <banman.h> + +#include <netaddress.h> +#include <ui_interface.h> +#include <util/system.h> +#include <util/time.h> + + +BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) + : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time) +{ + if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...")); + + int64_t n_start = GetTimeMillis(); + m_is_dirty = false; + banmap_t banmap; + if (m_ban_db.Read(banmap)) { + SetBanned(banmap); // thread save setter + SetBannedSetDirty(false); // no need to write down, just read data + SweepBanned(); // sweep out unused entries + + LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - n_start); + } else { + LogPrintf("Invalid or missing banlist.dat; recreating\n"); + SetBannedSetDirty(true); // force write + DumpBanlist(); + } +} + +BanMan::~BanMan() +{ + DumpBanlist(); +} + +void BanMan::DumpBanlist() +{ + SweepBanned(); // clean unused entries (if bantime has expired) + + if (!BannedSetIsDirty()) return; + + int64_t n_start = GetTimeMillis(); + + banmap_t banmap; + GetBanned(banmap); + if (m_ban_db.Write(banmap)) { + SetBannedSetDirty(false); + } + + LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - n_start); +} + +void BanMan::ClearBanned() +{ + { + LOCK(m_cs_banned); + m_banned.clear(); + m_is_dirty = true; + } + DumpBanlist(); //store banlist to disk + if (m_client_interface) m_client_interface->BannedListChanged(); +} + +bool BanMan::IsBanned(CNetAddr net_addr) +{ + LOCK(m_cs_banned); + for (const auto& it : m_banned) { + CSubNet sub_net = it.first; + CBanEntry ban_entry = it.second; + + if (sub_net.Match(net_addr) && GetTime() < ban_entry.nBanUntil) { + return true; + } + } + return false; +} + +bool BanMan::IsBanned(CSubNet sub_net) +{ + LOCK(m_cs_banned); + banmap_t::iterator i = m_banned.find(sub_net); + if (i != m_banned.end()) { + CBanEntry ban_entry = (*i).second; + if (GetTime() < ban_entry.nBanUntil) { + return true; + } + } + return false; +} + +void BanMan::Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch) +{ + CSubNet sub_net(net_addr); + Ban(sub_net, ban_reason, ban_time_offset, since_unix_epoch); +} + +void BanMan::Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch) +{ + CBanEntry ban_entry(GetTime(), ban_reason); + + int64_t normalized_ban_time_offset = ban_time_offset; + bool normalized_since_unix_epoch = since_unix_epoch; + if (ban_time_offset <= 0) { + normalized_ban_time_offset = m_default_ban_time; + normalized_since_unix_epoch = false; + } + ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset; + + { + LOCK(m_cs_banned); + if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) { + m_banned[sub_net] = ban_entry; + m_is_dirty = true; + } else + return; + } + if (m_client_interface) m_client_interface->BannedListChanged(); + + //store banlist to disk immediately if user requested ban + if (ban_reason == BanReasonManuallyAdded) DumpBanlist(); +} + +bool BanMan::Unban(const CNetAddr& net_addr) +{ + CSubNet sub_net(net_addr); + return Unban(sub_net); +} + +bool BanMan::Unban(const CSubNet& sub_net) +{ + { + LOCK(m_cs_banned); + if (m_banned.erase(sub_net) == 0) return false; + m_is_dirty = true; + } + if (m_client_interface) m_client_interface->BannedListChanged(); + DumpBanlist(); //store banlist to disk immediately + return true; +} + +void BanMan::GetBanned(banmap_t& banmap) +{ + LOCK(m_cs_banned); + // Sweep the banlist so expired bans are not returned + SweepBanned(); + banmap = m_banned; //create a thread safe copy +} + +void BanMan::SetBanned(const banmap_t& banmap) +{ + LOCK(m_cs_banned); + m_banned = banmap; + m_is_dirty = true; +} + +void BanMan::SweepBanned() +{ + int64_t now = GetTime(); + bool notify_ui = false; + { + LOCK(m_cs_banned); + banmap_t::iterator it = m_banned.begin(); + while (it != m_banned.end()) { + CSubNet sub_net = (*it).first; + CBanEntry ban_entry = (*it).second; + if (now > ban_entry.nBanUntil) { + m_banned.erase(it++); + m_is_dirty = true; + notify_ui = true; + LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString()); + } else + ++it; + } + } + // update UI + if (notify_ui && m_client_interface) { + m_client_interface->BannedListChanged(); + } +} + +bool BanMan::BannedSetIsDirty() +{ + LOCK(m_cs_banned); + return m_is_dirty; +} + +void BanMan::SetBannedSetDirty(bool dirty) +{ + LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag + m_is_dirty = dirty; +} |