From d504129cb7d1d69c2ce607aee59489001b100fb8 Mon Sep 17 00:00:00 2001 From: Intel Date: Sun, 4 May 2014 19:26:17 -0400 Subject: [PATCH] DoS protection --- src/server/poolserver/Stratum/Client.cpp | 38 ++++++++++++++++++- src/server/poolserver/Stratum/Client.h | 17 +++------ src/server/poolserver/Stratum/Server.h | 28 ++++++++++++++ .../poolserver/Stratum/ShareLimiter.cpp | 6 +++ src/server/poolserver/Stratum/ShareLimiter.h | 10 ++++- 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/server/poolserver/Stratum/Client.cpp b/src/server/poolserver/Stratum/Client.cpp index 0834209..af21a23 100644 --- a/src/server/poolserver/Stratum/Client.cpp +++ b/src/server/poolserver/Stratum/Client.cpp @@ -9,6 +9,22 @@ namespace Stratum { + void Client::Start() + { + // Get IP + tcp::endpoint remote_ep = _socket.remote_endpoint(); + address remote_ad = remote_ep.address(); + _ip = remote_ad.to_v4().to_ulong(); + + if (_server->IsBanned(_ip)) { + Disconnect(); + return; + } + + // Start reading socket + StartRead(); + } + void Client::SendJob(bool clean) { if (clean) @@ -92,6 +108,7 @@ namespace Stratum // Check if such job exists if (!_jobs.count(jobid)) { DataMgr::Instance()->Push(Share(_ip, username, false, "Job not found", Util::Date(), 1)); + _shareLimiter.LogBad(); JSON response; response["id"] = msg["id"]; @@ -150,6 +167,7 @@ namespace Stratum if (!job.SubmitShare(share.Binary())) { sLog.Error(LOG_SERVER, "Duplicate share"); DataMgr::Instance()->Push(Share(_ip, username, false, "Duplicate share", Util::Date(), job.diff)); + _shareLimiter.LogBad(); JSON response; response["id"] = msg["id"]; @@ -198,6 +216,7 @@ namespace Stratum if (target > Bitcoin::DiffToTarget(job.diff)) { sLog.Error(LOG_SERVER, "Share above target"); DataMgr::Instance()->Push(Share(_ip, username, false, "Share above target", Util::Date(), job.diff)); + _shareLimiter.LogBad(); JSON response; response["id"] = msg["id"]; @@ -213,7 +232,11 @@ namespace Stratum if (target <= criteria) { sLog.Info(LOG_SERVER, "We have found a block candidate!"); - _server->SubmitBlock(block); + if (_server->SubmitBlock(block)) { + std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, `time`, `difficulty`) VALUES "); + query += Util::FS("(INET_NTOA(%u), '%s', 1, 1, '', '%s', FROM_UNIXTIME(%u), %u)", _ip, username.c_str(), Util::BinToASCII(hash).c_str(), Util::Date(), job.diff); + sDatabase.ExecuteAsync(query.c_str()); + } } else { DataMgr::Instance()->Push(Share(_ip, username, true, "", Util::Date(), job.diff)); @@ -304,6 +327,17 @@ namespace Stratum return job; } + void Client::Ban(uint32 time) + { + _server->Ban(_ip, time); + Disconnect(); + } + + void Client::Disconnect() + { + _server->Disconnect(shared_from_this()); + } + void Client::_OnReceive(const boost::system::error_code& error, size_t bytes_transferred) { if (!error) { @@ -334,7 +368,7 @@ namespace Stratum } else { // Client disconnected if ((error == asio::error::eof) || (error == asio::error::connection_reset)) { - _server->Disconnect(shared_from_this()); + Disconnect(); } } } diff --git a/src/server/poolserver/Stratum/Client.h b/src/server/poolserver/Stratum/Client.h index d88f33a..a2da229 100644 --- a/src/server/poolserver/Stratum/Client.h +++ b/src/server/poolserver/Stratum/Client.h @@ -38,16 +38,8 @@ namespace Stratum return _socket; } - void Start() - { - // Get IP - tcp::endpoint remote_ep = _socket.remote_endpoint(); - address remote_ad = remote_ep.address(); - _ip = remote_ad.to_v4().to_ulong(); - - // Start reading socket - StartRead(); - } + // Start client up! + void Start(); void StartRead() { @@ -124,7 +116,10 @@ namespace Stratum return _id; } - void Disconnect() + void Ban(uint32 time); + void Disconnect(); + + void CloseSocket() { _socket.close(); } diff --git a/src/server/poolserver/Stratum/Server.h b/src/server/poolserver/Stratum/Server.h index c47d3e1..1be4ac9 100644 --- a/src/server/poolserver/Stratum/Server.h +++ b/src/server/poolserver/Stratum/Server.h @@ -16,6 +16,7 @@ #include #include #include +#include using namespace boost; using namespace boost::asio::ip; @@ -28,6 +29,12 @@ namespace Stratum uint16 Port; }; + struct BanInfo + { + uint32 ip; + uint64 timestamp; + }; + // Used for sorting std::set struct ClientPtrCMP { @@ -95,6 +102,26 @@ namespace Stratum _clients.erase(client); } + void Ban(uint32 ip, uint64 time) + { + BanInfo ban; + ban.ip = ip; + ban.timestamp = Util::Date() + time; + _bans.push_back(ban); + } + + bool IsBanned(uint32 ip) + { + for (int i = 0; i < _bans.size(); ++i) { + if (_bans[i].ip == ip) { + if (_bans[i].timestamp > Util::Date()) + return true; + } + } + + return false; + } + private: void _StartAccept() { @@ -123,6 +150,7 @@ namespace Stratum // Clients std::set _clients; + std::vector _bans; uint64 _clientId; // Work diff --git a/src/server/poolserver/Stratum/ShareLimiter.cpp b/src/server/poolserver/Stratum/ShareLimiter.cpp index 184a5e2..3cad777 100644 --- a/src/server/poolserver/Stratum/ShareLimiter.cpp +++ b/src/server/poolserver/Stratum/ShareLimiter.cpp @@ -8,6 +8,8 @@ namespace Stratum // Returning false will stop any further share verifications (DoS prevention, etc) bool ShareLimiter::Submit() { + ++_totalShares; + uint64 curTime = Util::Date(); uint64 sinceLast = curTime - _lastRetarget; @@ -18,6 +20,10 @@ namespace Stratum _lastRetarget = curTime; + // Check if miner is ok + if (_totalShares > 20 && (double(_totalBadShares)/double(_totalShares)) > 0.8) + _client->Ban(60); + while (_shares.size() && (_shares.front() < curTime - RETARGET_TIME_BUFFER)) _shares.pop_front(); diff --git a/src/server/poolserver/Stratum/ShareLimiter.h b/src/server/poolserver/Stratum/ShareLimiter.h index b65572e..b450b2b 100644 --- a/src/server/poolserver/Stratum/ShareLimiter.h +++ b/src/server/poolserver/Stratum/ShareLimiter.h @@ -19,7 +19,7 @@ namespace Stratum class ShareLimiter { public: - ShareLimiter(Client* client) : _client(client) + ShareLimiter(Client* client) : _client(client), _totalShares(0), _totalBadShares(0) { _startTime = Util::Date(); _lastRetarget = _startTime; @@ -27,11 +27,19 @@ namespace Stratum bool Submit(); + void LogBad() + { + ++_totalBadShares; + } + private: std::deque _shares; Client* _client; uint64 _lastRetarget; uint64 _startTime; + + uint64 _totalShares; + uint64 _totalBadShares; }; }