Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[P2P] Enforce expected outbound services #1616

Merged
merged 6 commits into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/activemasternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ void CActiveMasternode::ManageStatus()

LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString());

CNode* pnode = ConnectNode((CAddress)service, NULL, true);
CNode* pnode = ConnectNode(CAddress(service, NODE_NETWORK), NULL, true);
if (!pnode) {
notCapableReason = "Could not connect to " + service.ToString();
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
Expand Down Expand Up @@ -244,7 +244,7 @@ bool CActiveMasternode::CreateBroadcast(std::string strService, std::string strK
if(!CMasternodeBroadcast::CheckDefaultPort(strService, errorMessage, "CActiveMasternode::CreateBroadcast()"))
return false;

addrman.Add(CAddress(service), CNetAddr("127.0.0.1"), 2 * 60 * 60);
addrman.Add(CAddress(service, NODE_NETWORK), CNetAddr("127.0.0.1"), 2 * 60 * 60);

return CreateBroadcast(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb);
}
Expand Down
20 changes: 19 additions & 1 deletion src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);

// add services
pinfo->nServices |= addr.nServices;
pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);

// do not update if no new information is present
if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
Expand Down Expand Up @@ -503,6 +503,24 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime)
info.nTime = nTime;
}

void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
{
CAddrInfo* pinfo = Find(addr);

// if not found, bail out
if (!pinfo)
return;

CAddrInfo& info = *pinfo;

// check whether we are talking about the exact same CService (including same port)
if (info != addr)
return;

// update info
info.nServices = nServices;
}

int CAddrMan::RandomInt(int nMax){
return GetRandInt(nMax);
}
13 changes: 12 additions & 1 deletion src/addrman.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille
// Copyright (c) 2012-2014 The Bitcoin developers
// Copyright (c) 2012-2015 The Bitcoin developers
// Copyright (c) 2017-2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Expand Down Expand Up @@ -264,6 +264,9 @@ class CAddrMan
//! Mark an entry as currently-connected-to.
void Connected_(const CService& addr, int64_t nTime);

//! Update an entry's service bits.
void SetServices_(const CService& addr, ServiceFlags nServices);

public:
/**
* serialized format:
Expand Down Expand Up @@ -589,6 +592,14 @@ class CAddrMan
Check();
}
}

void SetServices(const CService& addr, ServiceFlags nServices)
{
LOCK(cs);
Check();
SetServices_(addr, nServices);
Check();
}
};

#endif // BITCOIN_ADDRMAN_H
4 changes: 2 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The NovaCoin Developers
Expand Down Expand Up @@ -1043,7 +1043,7 @@ bool AppInit2()
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);

if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices |= NODE_BLOOM;
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);

nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);

Expand Down
20 changes: 18 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The NovaCoin Developers
Expand Down Expand Up @@ -5233,7 +5233,20 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR
CAddress addrMe;
CAddress addrFrom;
uint64_t nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
uint64_t nServiceInt;
vRecv >> pfrom->nVersion >> nServiceInt >> nTime >> addrMe;
pfrom->nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound) {
addrman.SetServices(pfrom->addr, pfrom->nServices);
}
if (pfrom->nServicesExpected & ~pfrom->nServices) {
LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected);
pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
strprintf("Expected to offer services %08x", pfrom->nServicesExpected));
pfrom->fDisconnect = true;
return false;
}

if (pfrom->DisconnectOldProtocol(ActiveProtocol(), strCommand))
return false;

Expand Down Expand Up @@ -5383,6 +5396,9 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR
for (CAddress& addr : vAddr) {
boost::this_thread::interruption_point();

if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
continue;

if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
pfrom->AddAddressKnown(addr);
Expand Down
2 changes: 1 addition & 1 deletion src/masternodeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
// - this is checked later by .check() in many places and by ThreadCheckObfuScationPool()
if (mnb.CheckInputsAndAdd(nDoS)) {
// use this as a peer
addrman.Add(CAddress(mnb.addr), pfrom->addr, 2 * 60 * 60);
addrman.Add(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2 * 60 * 60);
masternodeSync.AddedMasternodeList(mnb.GetHash());
} else {
LogPrint(BCLog::MASTERNODE,"mnb - Rejected Masternode entry %s\n", mnb.vin.prevout.hash.ToString());
Expand Down
34 changes: 22 additions & 12 deletions src/net.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
Expand Down Expand Up @@ -67,12 +67,15 @@ struct ListenSocket {
};
}

/** Services this node implementation cares about */
static const ServiceFlags nRelevantServices = NODE_NETWORK;

//
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
ServiceFlags nLocalServices = NODE_NETWORK;
RecursiveMutex cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
Expand Down Expand Up @@ -157,7 +160,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6>& vSeedsIn
for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i) {
struct in6_addr ip;
memcpy(&ip, i->addr, sizeof(ip));
CAddress addr(CService(ip, i->port));
CAddress addr(CService(ip, i->port), NODE_NETWORK);
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
vSeedsOut.push_back(addr);
}
Expand All @@ -170,12 +173,11 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6>& vSeedsIn
// one by discovery.
CAddress GetLocalAddress(const CNetAddr* paddrPeer)
{
CAddress ret(CService("0.0.0.0", GetListenPort()), 0);
CAddress ret(CService("0.0.0.0", GetListenPort()), NODE_NONE);
CService addr;
if (GetLocal(addr, paddrPeer)) {
ret = CAddress(addr);
ret = CAddress(addr, nLocalServices);
}
ret.nServices = nLocalServices;
ret.nTime = GetAdjustedTime();
return ret;
}
Expand Down Expand Up @@ -446,6 +448,7 @@ CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool fCountFailure
vNodes.push_back(pnode);
}

pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
pnode->nTimeConnected = GetTime();

return pnode;
Expand Down Expand Up @@ -490,14 +493,14 @@ void CNode::PushVersion()

/// when NTP implemented, change to just nTime = GetAdjustedTime()
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0)));
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices));
CAddress addrMe = GetLocalAddress(&addr);
GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
if (fLogIPs)
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
else
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, strSubVersion, nBestHeight, true);
}

Expand Down Expand Up @@ -1298,7 +1301,7 @@ void ThreadDNSAddressSeed()
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
uint64_t requiredServiceBits = NODE_NETWORK;
ServiceFlags requiredServiceBits = nRelevantServices;
if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) {
for (CNetAddr& ip : vIPs) {
int nOneDay = 24 * 3600;
Expand Down Expand Up @@ -1366,7 +1369,7 @@ void ThreadOpenConnections()
for (int64_t nLoop = 0;; nLoop++) {
ProcessOneShot();
for (std::string strAddr : mapMultiArgs["-connect"]) {
CAddress addr;
CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, NULL, strAddr.c_str());
for (int i = 0; i < 10 && i < nLoop; i++) {
MilliSleep(500);
Expand Down Expand Up @@ -1435,6 +1438,10 @@ void ThreadOpenConnections()
if (IsLimited(addr))
continue;

// only connect to full nodes
if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
continue;

// only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
Expand Down Expand Up @@ -1512,7 +1519,9 @@ void ThreadOpenAddedConnections()
}
for (std::vector<CService>& vserv : lservAddressesToAdd) {
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant);
/* We want -addnode to work even for nodes that don't provide all
* wanted services, so pass in nServices=NODE_NONE to CAddress. */
OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant);
MilliSleep(500);
}
MilliSleep(120000); // Retry every 2 minutes
Expand Down Expand Up @@ -2107,7 +2116,8 @@ unsigned int SendBufferSize() { return 1000 * GetArg("-maxsendbuffer", 1 * 1000)

CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
{
nServices = 0;
nServices = NODE_NONE;
nServicesExpected = NODE_NONE;
hSocket = hSocketIn;
nRecvVersion = INIT_PROTO_VERSION;
nLastSend = 0;
Expand Down
11 changes: 7 additions & 4 deletions src/net.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2015-2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Expand Down Expand Up @@ -71,6 +71,8 @@ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** Maximum number of peers added to setOffsetDisconnectedPeers before triggering a warning */
#define MAX_TIMEOFFSET_DISCONNECTIONS 16

static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;

unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();

Expand Down Expand Up @@ -135,7 +137,7 @@ bool validateMasternodeIP(const std::string& addrStr); // valid, reacha

extern bool fDiscover;
extern bool fListen;
extern uint64_t nLocalServices;
extern ServiceFlags nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
extern int nMaxConnections;
Expand Down Expand Up @@ -168,7 +170,7 @@ class CNodeStats
{
public:
NodeId nodeid;
uint64_t nServices;
ServiceFlags nServices;
int64_t nLastSend;
int64_t nLastRecv;
int64_t nTimeConnected;
Expand Down Expand Up @@ -295,7 +297,8 @@ class CNode
{
public:
// socket
uint64_t nServices;
ServiceFlags nServices;
ServiceFlags nServicesExpected;
SOCKET hSocket;
CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries
Expand Down
4 changes: 2 additions & 2 deletions src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,15 @@ CAddress::CAddress() : CService()
Init();
}

CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn)
CAddress::CAddress(CService ipIn, ServiceFlags nServicesIn) : CService(ipIn)
{
Init();
nServices = nServicesIn;
}

void CAddress::Init()
{
nServices = NODE_NETWORK;
nServices = NODE_NONE;
nTime = 100000000;
}

Expand Down
22 changes: 14 additions & 8 deletions src/protocol.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2016-2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
Expand Down Expand Up @@ -283,17 +283,21 @@ extern const char* SYNCSTATUSCOUNT;
const std::vector<std::string>& getAllNetMessageTypes();

/** nServices flags */
enum {
enum ServiceFlags : uint64_t {
// Nothing
NODE_NONE = 0,
// NODE_NETWORK means that the node is capable of serving the block chain. It is currently
// set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want
// network services but don't provide them.
NODE_NETWORK = (1 << 0),

// NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.
// Bitcoin Core nodes used to support this by default, without advertising this bit,
// but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
NODE_BLOOM = (1 << 2),

// NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference
// that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here )

// NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference
// that the node doesn't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here )
NODE_BLOOM_WITHOUT_MN = (1 << 4),

// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
Expand All @@ -310,7 +314,7 @@ class CAddress : public CService
{
public:
CAddress();
explicit CAddress(CService ipIn, uint64_t nServicesIn = NODE_NETWORK);
explicit CAddress(CService ipIn, ServiceFlags nServicesIn);

void Init();

Expand All @@ -326,13 +330,15 @@ class CAddress : public CService
if ((nType & SER_DISK) ||
(nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
READWRITE(nTime);
READWRITE(nServices);
uint64_t nServicesInt = nServices;
READWRITE(nServicesInt);
nServices = (ServiceFlags)nServicesInt;
READWRITE(*(CService*)this);
}

// TODO: make private (improves encapsulation)
public:
uint64_t nServices;
ServiceFlags nServices;

// disk and network only
unsigned int nTime;
Expand Down
Loading