From 5d63086b69712802a5a95fc05dcb587ef6c7324d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 24 Sep 2013 13:00:11 -0700 Subject: [PATCH] Tie in blacklist code. --- src/ripple_app/main/LoadManager.cpp | 34 ++++++++++++++++---- src/ripple_app/main/LoadManager.h | 6 ++-- src/ripple_app/peers/Peer.cpp | 6 ++-- src/ripple_app/rpc/RPCHandler.cpp | 10 ++++++ src/ripple_app/rpc/RPCHandler.h | 1 + src/ripple_app/websocket/WSConnection.cpp | 8 ++++- src/ripple_basics/containers/BlackList.h | 39 ++++++++++++++++++++--- src/ripple_basics/ripple_basics.h | 1 + src/ripple_core/functional/LoadSource.h | 14 ++++++-- 9 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/ripple_app/main/LoadManager.cpp b/src/ripple_app/main/LoadManager.cpp index dc2a9ee184..28270d8985 100644 --- a/src/ripple_app/main/LoadManager.cpp +++ b/src/ripple_app/main/LoadManager.cpp @@ -146,7 +146,7 @@ private: } } - bool shouldWarn (LoadSource& source) const + bool shouldWarn (LoadSource& source) { { ScopedLockType sl (mLock, __FILE__, __LINE__); @@ -159,12 +159,14 @@ private: source.mLastWarning = now; } + mBlackList.doWarning(source.getCostName ()); logWarning (source.getName ()); return true; } - bool shouldCutoff (LoadSource& source) const + bool shouldCutoff (LoadSource& source) { + bool bLogged; { ScopedLockType sl (mLock, __FILE__, __LINE__); int now = UptimeTimer::getInstance ().getElapsedSeconds (); @@ -173,15 +175,22 @@ private: if (source.isPrivileged () || (source.mBalance > mDebitLimit)) return false; - if (source.mLogged) - return true; - + bLogged = source.mLogged; source.mLogged = true; } - logDisconnect (source.getName ()); + + mBlackList.doDisconnect (source.getName ()); + + if (!bLogged) + logDisconnect (source.getName ()); return true; } + bool shouldAllow (LoadSource& source) + { + return mBlackList.isAllowed (source.getCostName ()); + } + bool applyLoadCharge (LoadSource& source, LoadType loadType) const { // FIXME: Scale by category @@ -230,6 +239,17 @@ private: WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source; } + Json::Value getBlackList (int threshold) + { + Json::Value ret(Json::objectValue); + + BOOST_FOREACH(const BlackList::BlackListEntry& entry, mBlackList.getBlackList(threshold)) + { + ret[entry.first] = entry.second; + } + return ret; + } + // VFALCO TODO Implement this and stop accessing the vector directly //Cost const& getCost (LoadType loadType) const; int getCost (LoadType t) const @@ -415,6 +435,8 @@ private: beast::ThreadWithCallQueue m_logThread; + BlackList mBlackList; + int mCreditRate; // credits gained/lost per second int mCreditLimit; // the most credits a source can have int mDebitWarn; // when a source drops below this, we warn diff --git a/src/ripple_app/main/LoadManager.h b/src/ripple_app/main/LoadManager.h index 1a797ff99c..b036a05e21 100644 --- a/src/ripple_app/main/LoadManager.h +++ b/src/ripple_app/main/LoadManager.h @@ -80,8 +80,10 @@ public: // VFALCO TODO Eliminate these two functions and just make applyLoadCharge() // return a LoadSource::Disposition // - virtual bool shouldWarn (LoadSource&) const = 0; - virtual bool shouldCutoff (LoadSource&) const = 0; + virtual bool shouldWarn (LoadSource&) = 0; + virtual bool shouldCutoff (LoadSource&) = 0; + + virtual Json::Value getBlackList(int threshold = (BlackList::mCreditLimit / 2)) = 0; }; #endif diff --git a/src/ripple_app/peers/Peer.cpp b/src/ripple_app/peers/Peer.cpp index 052d3e07cb..8311e74326 100644 --- a/src/ripple_app/peers/Peer.cpp +++ b/src/ripple_app/peers/Peer.cpp @@ -71,7 +71,7 @@ public: , mCluster (false) , mPeerId (peerID) , mPrivate (false) - , mLoad (std::string()) + , mLoad (std::string(), std::string()) , mMinLedger (0) , mMaxLedger (0) , mActivityTimer (io_service) @@ -406,7 +406,7 @@ void PeerImp::handleWrite (const boost::system::error_code& error, size_t bytes_ void PeerImp::setIpPort (const std::string& strIP, int iPort) { mIpPort = make_pair (strIP, iPort); - mLoad.rename (strIP); + mLoad.rename (strIP + lexicalCast(iPort), strIP); WriteLog (lsDEBUG, Peer) << "Peer: Set: " << addressToString (this) << "> " @@ -1085,7 +1085,7 @@ void PeerImp::recvHello (protocol::TMHello& packet) mCluster = true; mLoad.setPrivileged (); if (!mNodeName.empty()) - mLoad.rename (mNodeName); + mLoad.rename (mNodeName, mNodeName); WriteLog (lsINFO, Peer) << "Cluster connection to \"" << (mNodeName.empty () ? getIP () : mNodeName) << "\" established"; } diff --git a/src/ripple_app/rpc/RPCHandler.cpp b/src/ripple_app/rpc/RPCHandler.cpp index 3d0765a762..d0563618d4 100644 --- a/src/ripple_app/rpc/RPCHandler.cpp +++ b/src/ripple_app/rpc/RPCHandler.cpp @@ -608,6 +608,15 @@ Json::Value RPCHandler::doAccountInfo (Json::Value params, LoadType* loadType, A return jvResult; } +Json::Value RPCHandler::doBlackList (Json::Value params, LoadType* loadType, Application::ScopedLockType& masterLockHolder) +{ + masterLockHolder.unlock(); + if (params.isMember("threshold")) + return getApp().getLoadManager().getBlackList(params["threshold"].asInt()); + else + return getApp().getLoadManager().getBlackList(); +} + // { // ip: , // port: @@ -3774,6 +3783,7 @@ Json::Value RPCHandler::doCommand (const Json::Value& params, int iRole, LoadTyp { "account_lines", &RPCHandler::doAccountLines, false, optCurrent }, { "account_offers", &RPCHandler::doAccountOffers, false, optCurrent }, { "account_tx", &RPCHandler::doAccountTxSwitch, false, optNetwork }, + { "blacklist", &RPCHandler::doBlackList, true, optNone }, { "book_offers", &RPCHandler::doBookOffers, false, optCurrent }, { "connect", &RPCHandler::doConnect, true, optNone }, { "consensus_info", &RPCHandler::doConsensusInfo, true, optNone }, diff --git a/src/ripple_app/rpc/RPCHandler.h b/src/ripple_app/rpc/RPCHandler.h index 153e4b8831..976f337a33 100644 --- a/src/ripple_app/rpc/RPCHandler.h +++ b/src/ripple_app/rpc/RPCHandler.h @@ -88,6 +88,7 @@ private: Json::Value doAccountTxSwitch (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); Json::Value doAccountTxOld (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); Json::Value doBookOffers (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); + Json::Value doBlackList (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); Json::Value doConnect (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); Json::Value doConsensusInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); Json::Value doFeature (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); diff --git a/src/ripple_app/websocket/WSConnection.cpp b/src/ripple_app/websocket/WSConnection.cpp index 10048f0ce5..98c5bf76a2 100644 --- a/src/ripple_app/websocket/WSConnection.cpp +++ b/src/ripple_app/websocket/WSConnection.cpp @@ -6,6 +6,12 @@ SETUP_LOGN (WSConnection, "WSConnection") +static std::string trimIP(const std::string& ip) +{ // Make sure there's no port + size_t pos = ip.find(':'); + return (pos == std::string::npos) ? ip : ip.substr(0, pos - 1); +} + //------------------------------------------------------------------------------ WSConnection::WSConnection (InfoSub::Source& source, bool isPublic, @@ -15,7 +21,7 @@ WSConnection::WSConnection (InfoSub::Source& source, bool isPublic, , m_remoteIP (remoteIP) , m_receiveQueueMutex (this, "WSConnection", __FILE__, __LINE__) , m_netOPs (getApp ().getOPs ()) - , m_loadSource (m_remoteIP) + , m_loadSource (m_remoteIP, trimIP(m_remoteIP)) , m_pingTimer (io_service) , m_sentPing (false) , m_receiveQueueRunning (false) diff --git a/src/ripple_basics/containers/BlackList.h b/src/ripple_basics/containers/BlackList.h index 247c2a4721..e59f6052c1 100644 --- a/src/ripple_basics/containers/BlackList.h +++ b/src/ripple_basics/containers/BlackList.h @@ -10,8 +10,11 @@ class BlackList int mBalance; // Exponentially-decaying "cost" balance int mLastUpdate; // The uptime when the balance was last decayed - iBlackList(int now) : mBalance(0), mLastUpdate(now) { ; } - iBlackList() : mBalance(0), mLastUpdate(0) { ; } + iBlackList(int now) : mBalance(0), mLastUpdate(now) + { ; } + + iBlackList() : mBalance(0), mLastUpdate(0) + { ; } }; public: @@ -21,7 +24,11 @@ public: typedef std::vector BlackListEntryList; BlackList() - { } + { + mWhiteList.push_back("127."); + mWhiteList.push_back("10."); + mWhiteList.push_back("192.168."); + } // We are issuing a warning to a source, update its entry bool doWarning(const std::string& source) @@ -107,6 +114,27 @@ public: } } + void setWhiteList(std::vector wl) + { + boost::mutex::scoped_lock sl(mMutex); + + mWhiteList.swap(wl); + } + + bool isWhiteList(const std::string& source) + { + { + boost::mutex::scoped_lock sl(mMutex); + BOOST_FOREACH(const std::string& entry, mWhiteList) + { // Does this source start with the entry? + if ((source.size() >= entry.size()) && (entry.compare(0, entry.size(), source) == 0)) + return true; + } + } + + return false; + } + static const int mWarnCost = 10; // The cost of being warned static const int mDiscCost = 100; // The cost of being disconnected for abuse static const int mRejectCost = 1; // The cost of having a connection disconnected @@ -119,8 +147,9 @@ private: typedef std::map BlackListTable; - BlackListTable mList; - boost::mutex mMutex; + BlackListTable mList; + std::vector mWhiteList; + boost::mutex mMutex; bool chargeEntry(const std::string& source, int charge) { diff --git a/src/ripple_basics/ripple_basics.h b/src/ripple_basics/ripple_basics.h index a5abb62769..0ca6e434d7 100644 --- a/src/ripple_basics/ripple_basics.h +++ b/src/ripple_basics/ripple_basics.h @@ -69,6 +69,7 @@ using namespace beast; #include "containers/KeyCache.h" #include "containers/RangeSet.h" +#include "containers/BlackList.h" #include "containers/TaggedCache.h" } diff --git a/src/ripple_core/functional/LoadSource.h b/src/ripple_core/functional/LoadSource.h index f56dbb7e53..6aa68007da 100644 --- a/src/ripple_core/functional/LoadSource.h +++ b/src/ripple_core/functional/LoadSource.h @@ -63,8 +63,9 @@ public: /** Construct a load source with a given name. The endpoint is considered non-privileged. */ - explicit LoadSource (std::string const& name) + explicit LoadSource (std::string const& name, std::string const& costName) : mName (name) + , mCostName (costName) , mBalance (0) , mFlags (0) , mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ()) @@ -81,9 +82,10 @@ public: // VFALCO TODO Figure out a way to construct the LoadSource object with // the proper name instead of renaming it later. // - void rename (std::string const& name) noexcept + void rename (std::string const& name, std::string const& costName) noexcept { mName = name; + mCostName = costName; } /** Retrieve the name of this endpoint. @@ -93,6 +95,11 @@ public: return mName; } + std::string const& getCostName () const noexcept + { + return mCostName; + } + /** Determine if this endpoint is privileged. */ bool isPrivileged () const noexcept @@ -154,7 +161,8 @@ private: static const int lsfOutbound = 2; private: - std::string mName; + std::string mName; // Name of this particular load source, can include details like ports + std::string mCostName; // The name to "charge" for load from this connection int mBalance; int mFlags; int mLastUpdate;