mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-12 08:08:25 +00:00
Framework for banning mis-behaving peers
This commit is contained in:
parent
54d02f158d
commit
15f3ad4dbd
@ -179,6 +179,8 @@ bool AppInit2(int argc, char* argv[])
|
|||||||
" -addnode=<ip> \t " + _("Add a node to connect to\n") +
|
" -addnode=<ip> \t " + _("Add a node to connect to\n") +
|
||||||
" -connect=<ip> \t\t " + _("Connect only to the specified node\n") +
|
" -connect=<ip> \t\t " + _("Connect only to the specified node\n") +
|
||||||
" -nolisten \t " + _("Don't accept connections from outside\n") +
|
" -nolisten \t " + _("Don't accept connections from outside\n") +
|
||||||
|
" -banscore=<n> \t " + _("Threshold for disconnecting misbehaving peers (default: 100)\n") +
|
||||||
|
" -bantime=<n> \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") +
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
#if USE_UPNP
|
#if USE_UPNP
|
||||||
" -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") +
|
" -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") +
|
||||||
|
54
src/net.cpp
54
src/net.cpp
@ -726,6 +726,52 @@ void CNode::Cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::map<unsigned int, int64> CNode::setBanned;
|
||||||
|
CCriticalSection CNode::cs_setBanned;
|
||||||
|
|
||||||
|
void CNode::ClearBanned()
|
||||||
|
{
|
||||||
|
setBanned.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNode::IsBanned(unsigned int ip)
|
||||||
|
{
|
||||||
|
bool fResult = false;
|
||||||
|
CRITICAL_BLOCK(cs_setBanned)
|
||||||
|
{
|
||||||
|
std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
|
||||||
|
if (i != setBanned.end())
|
||||||
|
{
|
||||||
|
int64 t = (*i).second;
|
||||||
|
if (GetTime() < t)
|
||||||
|
fResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNode::Misbehaving(int howmuch)
|
||||||
|
{
|
||||||
|
if (addr.IsLocal())
|
||||||
|
{
|
||||||
|
printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nMisbehavior += howmuch;
|
||||||
|
if (nMisbehavior >= GetArg("-banscore", 100))
|
||||||
|
{
|
||||||
|
int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
|
||||||
|
CRITICAL_BLOCK(cs_setBanned)
|
||||||
|
if (setBanned[addr.ip] < banTime)
|
||||||
|
setBanned[addr.ip] = banTime;
|
||||||
|
CloseSocketDisconnect();
|
||||||
|
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -896,6 +942,11 @@ void ThreadSocketHandler2(void* parg)
|
|||||||
{
|
{
|
||||||
closesocket(hSocket);
|
closesocket(hSocket);
|
||||||
}
|
}
|
||||||
|
else if (CNode::IsBanned(addr.ip))
|
||||||
|
{
|
||||||
|
printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
|
||||||
|
closesocket(hSocket);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("accepted connection %s\n", addr.ToString().c_str());
|
printf("accepted connection %s\n", addr.ToString().c_str());
|
||||||
@ -1454,7 +1505,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect)
|
|||||||
//
|
//
|
||||||
if (fShutdown)
|
if (fShutdown)
|
||||||
return false;
|
return false;
|
||||||
if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
|
if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
|
||||||
|
FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vnThreadsRunning[1]--;
|
vnThreadsRunning[1]--;
|
||||||
|
28
src/net.h
28
src/net.h
@ -124,6 +124,13 @@ public:
|
|||||||
bool fDisconnect;
|
bool fDisconnect;
|
||||||
protected:
|
protected:
|
||||||
int nRefCount;
|
int nRefCount;
|
||||||
|
|
||||||
|
// Denial-of-service detection/prevention
|
||||||
|
// Key is ip address, value is banned-until-time
|
||||||
|
static std::map<unsigned int, int64> setBanned;
|
||||||
|
static CCriticalSection cs_setBanned;
|
||||||
|
int nMisbehavior;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int64 nReleaseTime;
|
int64 nReleaseTime;
|
||||||
std::map<uint256, CRequestTracker> mapRequests;
|
std::map<uint256, CRequestTracker> mapRequests;
|
||||||
@ -148,7 +155,6 @@ public:
|
|||||||
// publish and subscription
|
// publish and subscription
|
||||||
std::vector<char> vfSubscribe;
|
std::vector<char> vfSubscribe;
|
||||||
|
|
||||||
|
|
||||||
CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
|
CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
|
||||||
{
|
{
|
||||||
nServices = 0;
|
nServices = 0;
|
||||||
@ -185,6 +191,7 @@ public:
|
|||||||
nStartingHeight = -1;
|
nStartingHeight = -1;
|
||||||
fGetAddr = false;
|
fGetAddr = false;
|
||||||
vfSubscribe.assign(256, false);
|
vfSubscribe.assign(256, false);
|
||||||
|
nMisbehavior = 0;
|
||||||
|
|
||||||
// Be shy and don't send version until we hear
|
// Be shy and don't send version until we hear
|
||||||
if (!fInbound)
|
if (!fInbound)
|
||||||
@ -568,6 +575,25 @@ public:
|
|||||||
void CancelSubscribe(unsigned int nChannel);
|
void CancelSubscribe(unsigned int nChannel);
|
||||||
void CloseSocketDisconnect();
|
void CloseSocketDisconnect();
|
||||||
void Cleanup();
|
void Cleanup();
|
||||||
|
|
||||||
|
|
||||||
|
// Denial-of-service detection/prevention
|
||||||
|
// The idea is to detect peers that are behaving
|
||||||
|
// badly and disconnect/ban them, but do it in a
|
||||||
|
// one-coding-mistake-won't-shatter-the-entire-network
|
||||||
|
// way.
|
||||||
|
// IMPORTANT: There should be nothing I can give a
|
||||||
|
// node that it will forward on that will make that
|
||||||
|
// node's peers drop it. If there is, an attacker
|
||||||
|
// can isolate a node and/or try to split the network.
|
||||||
|
// Dropping a node for sending stuff that is invalid
|
||||||
|
// now but might be valid in a later version is also
|
||||||
|
// dangerous, because it can cause a network split
|
||||||
|
// between nodes running old code and nodes running
|
||||||
|
// new code.
|
||||||
|
static void ClearBanned(); // needed for unit testing
|
||||||
|
static bool IsBanned(unsigned int ip);
|
||||||
|
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
68
src/test/DoS_tests.cpp
Normal file
68
src/test/DoS_tests.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// Unit tests for denial-of-service detection/prevention code
|
||||||
|
//
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
#include "../main.h"
|
||||||
|
#include "../net.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(DoS_tests)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(DoS_banning)
|
||||||
|
{
|
||||||
|
CNode::ClearBanned();
|
||||||
|
CAddress addr1(0xa0b0c001);
|
||||||
|
CNode dummyNode1(INVALID_SOCKET, addr1, true);
|
||||||
|
dummyNode1.Misbehaving(100); // Should get banned
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr1.ip));
|
||||||
|
BOOST_CHECK(!CNode::IsBanned(addr1.ip|0x0000ff00)); // Different ip, not banned
|
||||||
|
|
||||||
|
CAddress addr2(0xa0b0c002);
|
||||||
|
CNode dummyNode2(INVALID_SOCKET, addr2, true);
|
||||||
|
dummyNode2.Misbehaving(50);
|
||||||
|
BOOST_CHECK(!CNode::IsBanned(addr2.ip)); // 2 not banned yet...
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr1.ip)); // ... but 1 still should be
|
||||||
|
dummyNode2.Misbehaving(50);
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr2.ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(DoS_banscore)
|
||||||
|
{
|
||||||
|
CNode::ClearBanned();
|
||||||
|
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
|
||||||
|
CAddress addr1(0xa0b0c001);
|
||||||
|
CNode dummyNode1(INVALID_SOCKET, addr1, true);
|
||||||
|
dummyNode1.Misbehaving(100);
|
||||||
|
BOOST_CHECK(!CNode::IsBanned(addr1.ip));
|
||||||
|
dummyNode1.Misbehaving(10);
|
||||||
|
BOOST_CHECK(!CNode::IsBanned(addr1.ip));
|
||||||
|
dummyNode1.Misbehaving(1);
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr1.ip));
|
||||||
|
mapArgs["-banscore"] = "100";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||||
|
{
|
||||||
|
CNode::ClearBanned();
|
||||||
|
int64 nStartTime = GetTime();
|
||||||
|
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||||
|
|
||||||
|
CAddress addr(0xa0b0c001);
|
||||||
|
CNode dummyNode(INVALID_SOCKET, addr, true);
|
||||||
|
|
||||||
|
dummyNode.Misbehaving(100);
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr.ip));
|
||||||
|
|
||||||
|
SetMockTime(nStartTime+60*60);
|
||||||
|
BOOST_CHECK(CNode::IsBanned(addr.ip));
|
||||||
|
|
||||||
|
SetMockTime(nStartTime+60*60*24+1);
|
||||||
|
BOOST_CHECK(!CNode::IsBanned(addr.ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
@ -8,7 +8,7 @@
|
|||||||
#include "uint256_tests.cpp"
|
#include "uint256_tests.cpp"
|
||||||
#include "script_tests.cpp"
|
#include "script_tests.cpp"
|
||||||
#include "transaction_tests.cpp"
|
#include "transaction_tests.cpp"
|
||||||
|
#include "DoS_tests.cpp"
|
||||||
|
|
||||||
CWallet* pwalletMain;
|
CWallet* pwalletMain;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user