Merge pull request #4378
dc942e6
Introduce whitelisted peers. (Pieter Wuille)
This commit is contained in:
commit
c9bc398ad9
@ -10,7 +10,7 @@ touch "$DATADIR/regtest/debug.log"
|
||||
tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
|
||||
WAITER=$!
|
||||
PORT=`expr $BASHPID + 10000`
|
||||
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -regtest -rpcport=`expr $PORT + 1` &
|
||||
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
|
||||
BITCOIND=$!
|
||||
|
||||
#Install a watchdog.
|
||||
|
32
src/init.cpp
32
src/init.cpp
@ -58,7 +58,8 @@ CWallet* pwalletMain;
|
||||
enum BindFlags {
|
||||
BF_NONE = 0,
|
||||
BF_EXPLICIT = (1U << 0),
|
||||
BF_REPORT_ERROR = (1U << 1)
|
||||
BF_REPORT_ERROR = (1U << 1),
|
||||
BF_WHITELIST = (1U << 2),
|
||||
};
|
||||
|
||||
static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
|
||||
@ -192,7 +193,7 @@ bool static Bind(const CService &addr, unsigned int flags) {
|
||||
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
|
||||
return false;
|
||||
std::string strError;
|
||||
if (!BindListenPort(addr, strError)) {
|
||||
if (!BindListenPort(addr, strError, flags & BF_WHITELIST)) {
|
||||
if (flags & BF_REPORT_ERROR)
|
||||
return InitError(strError);
|
||||
return false;
|
||||
@ -252,6 +253,8 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n";
|
||||
#endif
|
||||
#endif
|
||||
strUsage += " -whitebind=<addr> " + _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6") + "\n";
|
||||
strUsage += " -whitelist=<netmask> " + _("Whitelist peers connecting from the given netmask or ip. Can be specified multiple times.") + "\n";
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
strUsage += "\n" + _("Wallet options:") + "\n";
|
||||
@ -506,11 +509,11 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
|
||||
// ********************************************************* Step 2: parameter interactions
|
||||
|
||||
if (mapArgs.count("-bind")) {
|
||||
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
|
||||
// when specifying an explicit binding address, you want to listen on it
|
||||
// even when -connect or -proxy is specified
|
||||
if (SoftSetBoolArg("-listen", true))
|
||||
LogPrintf("AppInit2 : parameter interaction: -bind set -> setting -listen=1\n");
|
||||
LogPrintf("AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1\n");
|
||||
}
|
||||
|
||||
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) {
|
||||
@ -554,7 +557,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
}
|
||||
|
||||
// Make sure enough file descriptors are available
|
||||
int nBind = std::max((int)mapArgs.count("-bind"), 1);
|
||||
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
|
||||
nMaxConnections = GetArg("-maxconnections", 125);
|
||||
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
|
||||
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
|
||||
@ -771,6 +774,15 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
}
|
||||
}
|
||||
|
||||
if (mapArgs.count("-whitelist")) {
|
||||
BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) {
|
||||
CSubNet subnet(net);
|
||||
if (!subnet.IsValid())
|
||||
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
|
||||
CNode::AddWhitelistedRange(subnet);
|
||||
}
|
||||
}
|
||||
|
||||
CService addrProxy;
|
||||
bool fProxy = false;
|
||||
if (mapArgs.count("-proxy")) {
|
||||
@ -807,13 +819,21 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
|
||||
bool fBound = false;
|
||||
if (fListen) {
|
||||
if (mapArgs.count("-bind")) {
|
||||
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
|
||||
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
|
||||
CService addrBind;
|
||||
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
|
||||
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
|
||||
}
|
||||
BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) {
|
||||
CService addrBind;
|
||||
if (!Lookup(strBind.c_str(), addrBind, 0, false))
|
||||
return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
|
||||
if (addrBind.GetPort() == 0)
|
||||
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct in_addr inaddr_any;
|
||||
|
19
src/main.cpp
19
src/main.cpp
@ -212,7 +212,7 @@ struct CBlockReject {
|
||||
struct CNodeState {
|
||||
// Accumulated misbehaviour score for this peer.
|
||||
int nMisbehavior;
|
||||
// Whether this peer should be disconnected and banned.
|
||||
// Whether this peer should be disconnected and banned (unless whitelisted).
|
||||
bool fShouldBan;
|
||||
// String name of this peer (debugging/logging purposes).
|
||||
std::string name;
|
||||
@ -1427,7 +1427,8 @@ void Misbehaving(NodeId pnode, int howmuch)
|
||||
return;
|
||||
|
||||
state->nMisbehavior += howmuch;
|
||||
if (state->nMisbehavior >= GetArg("-banscore", 100))
|
||||
int banscore = GetArg("-banscore", 100);
|
||||
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
|
||||
{
|
||||
LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
|
||||
state->fShouldBan = true;
|
||||
@ -3952,6 +3953,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
|
||||
if (nEvicted > 0)
|
||||
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
|
||||
} else if (pfrom->fWhitelisted) {
|
||||
// Always relay transactions received from whitelisted peers, even
|
||||
// if they are already in the mempool (allowing the node to function
|
||||
// as a gateway for nodes hidden behind it).
|
||||
RelayTransaction(tx);
|
||||
}
|
||||
int nDoS = 0;
|
||||
if (state.IsInvalid(nDoS))
|
||||
@ -4445,11 +4451,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
|
||||
CNodeState &state = *State(pto->GetId());
|
||||
if (state.fShouldBan) {
|
||||
if (pto->addr.IsLocal())
|
||||
LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString());
|
||||
if (pto->fWhitelisted)
|
||||
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
|
||||
else {
|
||||
pto->fDisconnect = true;
|
||||
CNode::Ban(pto->addr);
|
||||
if (pto->addr.IsLocal())
|
||||
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
|
||||
else
|
||||
CNode::Ban(pto->addr);
|
||||
}
|
||||
state.fShouldBan = false;
|
||||
}
|
||||
|
60
src/net.cpp
60
src/net.cpp
@ -50,7 +50,16 @@
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
static const int MAX_OUTBOUND_CONNECTIONS = 8;
|
||||
namespace {
|
||||
const int MAX_OUTBOUND_CONNECTIONS = 8;
|
||||
|
||||
struct ListenSocket {
|
||||
SOCKET socket;
|
||||
bool whitelisted;
|
||||
|
||||
ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Global state variables
|
||||
@ -65,7 +74,7 @@ static bool vfLimited[NET_MAX] = {};
|
||||
static CNode* pnodeLocalHost = NULL;
|
||||
static CNode* pnodeSync = NULL;
|
||||
uint64_t nLocalHostNonce = 0;
|
||||
static std::vector<SOCKET> vhListenSocket;
|
||||
static std::vector<ListenSocket> vhListenSocket;
|
||||
CAddrMan addrman;
|
||||
int nMaxConnections = 125;
|
||||
|
||||
@ -593,6 +602,24 @@ bool CNode::Ban(const CNetAddr &addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<CSubNet> CNode::vWhitelistedRange;
|
||||
CCriticalSection CNode::cs_vWhitelistedRange;
|
||||
|
||||
bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
|
||||
LOCK(cs_vWhitelistedRange);
|
||||
BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
|
||||
if (subnet.Match(addr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CNode::AddWhitelistedRange(const CSubNet &subnet) {
|
||||
LOCK(cs_vWhitelistedRange);
|
||||
vWhitelistedRange.push_back(subnet);
|
||||
}
|
||||
|
||||
#undef X
|
||||
#define X(name) stats.name = name
|
||||
void CNode::copyStats(CNodeStats &stats)
|
||||
@ -609,6 +636,7 @@ void CNode::copyStats(CNodeStats &stats)
|
||||
X(nStartingHeight);
|
||||
X(nSendBytes);
|
||||
X(nRecvBytes);
|
||||
X(fWhitelisted);
|
||||
stats.fSyncNode = (this == pnodeSync);
|
||||
|
||||
// It is common for nodes with good ping times to suddenly become lagged,
|
||||
@ -848,9 +876,9 @@ void ThreadSocketHandler()
|
||||
SOCKET hSocketMax = 0;
|
||||
bool have_fds = false;
|
||||
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
|
||||
FD_SET(hListenSocket, &fdsetRecv);
|
||||
hSocketMax = max(hSocketMax, hListenSocket);
|
||||
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
|
||||
FD_SET(hListenSocket.socket, &fdsetRecv);
|
||||
hSocketMax = max(hSocketMax, hListenSocket.socket);
|
||||
have_fds = true;
|
||||
}
|
||||
|
||||
@ -917,13 +945,13 @@ void ThreadSocketHandler()
|
||||
//
|
||||
// Accept new connections
|
||||
//
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
|
||||
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
|
||||
{
|
||||
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
|
||||
if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
|
||||
{
|
||||
struct sockaddr_storage sockaddr;
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
|
||||
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
|
||||
CAddress addr;
|
||||
int nInbound = 0;
|
||||
|
||||
@ -931,6 +959,7 @@ void ThreadSocketHandler()
|
||||
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
|
||||
LogPrintf("Warning: Unknown socket family\n");
|
||||
|
||||
bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
@ -948,7 +977,7 @@ void ThreadSocketHandler()
|
||||
{
|
||||
closesocket(hSocket);
|
||||
}
|
||||
else if (CNode::IsBanned(addr))
|
||||
else if (CNode::IsBanned(addr) && !whitelisted)
|
||||
{
|
||||
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
|
||||
closesocket(hSocket);
|
||||
@ -957,6 +986,7 @@ void ThreadSocketHandler()
|
||||
{
|
||||
CNode* pnode = new CNode(hSocket, addr, "", true);
|
||||
pnode->AddRef();
|
||||
pnode->fWhitelisted = whitelisted;
|
||||
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
@ -1580,7 +1610,7 @@ void ThreadMessageHandler()
|
||||
|
||||
|
||||
|
||||
bool BindListenPort(const CService &addrBind, string& strError)
|
||||
bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
|
||||
{
|
||||
strError = "";
|
||||
int nOne = 1;
|
||||
@ -1661,9 +1691,9 @@ bool BindListenPort(const CService &addrBind, string& strError)
|
||||
return false;
|
||||
}
|
||||
|
||||
vhListenSocket.push_back(hListenSocket);
|
||||
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
|
||||
|
||||
if (addrBind.IsRoutable() && fDiscover)
|
||||
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
|
||||
AddLocal(addrBind, LOCAL_BIND);
|
||||
|
||||
return true;
|
||||
@ -1788,9 +1818,9 @@ public:
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
if (pnode->hSocket != INVALID_SOCKET)
|
||||
closesocket(pnode->hSocket);
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
|
||||
if (hListenSocket != INVALID_SOCKET)
|
||||
if (closesocket(hListenSocket) == SOCKET_ERROR)
|
||||
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
|
||||
if (hListenSocket.socket != INVALID_SOCKET)
|
||||
if (closesocket(hListenSocket.socket) == SOCKET_ERROR)
|
||||
LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
||||
|
||||
// clean up some globals (to help leak detection)
|
||||
|
13
src/net.h
13
src/net.h
@ -64,7 +64,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
|
||||
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
|
||||
void MapPort(bool fUseUPnP);
|
||||
unsigned short GetListenPort();
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError);
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
|
||||
void StartNode(boost::thread_group& threadGroup);
|
||||
bool StopNode();
|
||||
void SocketSendData(CNode *pnode);
|
||||
@ -154,6 +154,7 @@ public:
|
||||
uint64_t nSendBytes;
|
||||
uint64_t nRecvBytes;
|
||||
bool fSyncNode;
|
||||
bool fWhitelisted;
|
||||
double dPingTime;
|
||||
double dPingWait;
|
||||
std::string addrLocal;
|
||||
@ -236,6 +237,7 @@ public:
|
||||
// store the sanitized version in cleanSubVer. The original should be used when dealing with
|
||||
// the network or wire types and the cleaned string used when displayed or logged.
|
||||
std::string strSubVer, cleanSubVer;
|
||||
bool fWhitelisted; // This peer can bypass DoS banning.
|
||||
bool fOneShot;
|
||||
bool fClient;
|
||||
bool fInbound;
|
||||
@ -259,6 +261,11 @@ protected:
|
||||
static std::map<CNetAddr, int64_t> setBanned;
|
||||
static CCriticalSection cs_setBanned;
|
||||
|
||||
// Whitelisted ranges. Any node connecting from these is automatically
|
||||
// whitelisted (as well as those connecting to whitelisted binds).
|
||||
static std::vector<CSubNet> vWhitelistedRange;
|
||||
static CCriticalSection cs_vWhitelistedRange;
|
||||
|
||||
// Basic fuzz-testing
|
||||
void Fuzz(int nChance); // modifies ssSend
|
||||
|
||||
@ -305,6 +312,7 @@ public:
|
||||
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
|
||||
nVersion = 0;
|
||||
strSubVer = "";
|
||||
fWhitelisted = false;
|
||||
fOneShot = false;
|
||||
fClient = false; // set by version message
|
||||
fInbound = fInboundIn;
|
||||
@ -720,6 +728,9 @@ public:
|
||||
static bool Ban(const CNetAddr &ip);
|
||||
void copyStats(CNodeStats &stats);
|
||||
|
||||
static bool IsWhitelistedRange(const CNetAddr &ip);
|
||||
static void AddWhitelistedRange(const CSubNet &subnet);
|
||||
|
||||
// Network stats
|
||||
static void RecordBytesRecv(uint64_t bytes);
|
||||
static void RecordBytesSent(uint64_t bytes);
|
||||
|
@ -137,6 +137,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
||||
obj.push_back(Pair("syncheight", statestats.nSyncHeight));
|
||||
}
|
||||
obj.push_back(Pair("syncnode", stats.fSyncNode));
|
||||
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
|
||||
|
||||
ret.push_back(obj);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user