Skip to content

Commit

Permalink
Added feeler connections increasing good addrs in the tried table. (#…
Browse files Browse the repository at this point in the history
…1530)

Tests if addresses are online or offline by briefly connecting to them. These short lived connections are referred to as feeler connections. Feeler connections are designed to increase the number of fresh online addresses in tried by selecting and connecting to addresses in new. One feeler connection is attempted on average once every two minutes.

This change was suggested as Countermeasure 4 in
Eclipse Attacks on Bitcoin’s Peer-to-Peer Network, Ethan Heilman,
Alison Kendler, Aviv Zohar, Sharon Goldberg. ePrint Archive Report
2015/263. March 2015.
  • Loading branch information
OlegGirko authored and UdjinM6 committed Jul 17, 2017
1 parent 27b6f36 commit d934ffb
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5284,6 +5284,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

if (strCommand == NetMsgType::VERSION)
{
// Feeler connections exist only to verify if address is online.
if (pfrom->fFeeler) {
assert(pfrom->fInbound == false);
pfrom->fDisconnect = true;
}

// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
Expand Down
59 changes: 51 additions & 8 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900

// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1

#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
Expand All @@ -67,6 +70,7 @@
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
const int MAX_OUTBOUND_MASTERNODE_CONNECTIONS = 20;
const int MAX_FEELER_CONNECTIONS = 1;

struct ListenSocket {
SOCKET socket;
Expand Down Expand Up @@ -1053,7 +1057,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
assert(nMaxInbound > 0);

if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
Expand Down Expand Up @@ -1627,6 +1632,9 @@ void ThreadOpenConnections()

// Initiate network connections
int64_t nStart = GetTime();

// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true)
{
ProcessOneShot();
Expand Down Expand Up @@ -1664,13 +1672,36 @@ void ThreadOpenConnections()
}
}
}
assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));

int64_t nANow = GetAdjustedTime();
// Feeler Connections
//
// Design goals:
// * Increase the number of connectable addresses in the tried table.
//
// Method:
// * Choose a random address from new and attempt to connect to it if we can connect
// successfully it is added to tried.
// * Start attempting feeler connections only after node finishes making outbound
// connections.
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false;
if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
fFeeler = true;
} else {
continue;
}
}

int64_t nANow = GetAdjustedTime();
int nTries = 0;
while (true)
{
CAddrInfo addr = addrman.Select();
CAddrInfo addr = addrman.Select(fFeeler);

// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
Expand Down Expand Up @@ -1702,8 +1733,17 @@ void ThreadOpenConnections()
break;
}

if (addrConnect.IsValid())
OpenNetworkConnection(addrConnect, &grant);
if (addrConnect.IsValid()) {

if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization.
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
MilliSleep(randsleep);
LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
}

OpenNetworkConnection(addrConnect, &grant, NULL, false, fFeeler);
}
}
}

Expand Down Expand Up @@ -1829,7 +1869,7 @@ void ThreadMnbRequestConnections()
}

// if successful, this moves the passed grant to the constructed node
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{
//
// Initiate outbound network connection
Expand All @@ -1852,6 +1892,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
grantOutbound->MoveTo(pnode->grantOutbound);
if (fOneShot)
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;

return true;
}
Expand Down Expand Up @@ -2101,7 +2143,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)

if (semOutbound == NULL) {
// initialize semaphore
int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}

Expand Down Expand Up @@ -2151,7 +2193,7 @@ bool StopNode()
LogPrintf("StopNode()\n");
MapPort(false);
if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();

if (semMasternodeOutbound)
Expand Down Expand Up @@ -2554,6 +2596,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = fNetworkNodeIn;
fSuccessfullyConnected = false;
Expand Down
5 changes: 4 additions & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ static const int PING_INTERVAL = 2 * 60;
static const int TIMEOUT_INTERVAL = 20 * 60;
/** Minimum time between warnings printed to log. */
static const int WARNING_INTERVAL = 10 * 60;
/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
static const int FEELER_INTERVAL = 120;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */
Expand Down Expand Up @@ -91,7 +93,7 @@ CNode* FindNode(const CService& ip);
// fConnectToMasternode should be 'true' only if you want this node to allow to connect to itself
// and/or you want it to be disconnected on CMasternodeMan::ProcessMasternodeConnections()
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL, bool fConnectToMasternode = false);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
Expand Down Expand Up @@ -357,6 +359,7 @@ class CNode
// 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 fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fClient;
bool fInbound;
Expand Down
22 changes: 22 additions & 0 deletions src/test/net_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,26 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman2.size() == 0);
}

BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;

in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;

CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest = "";
bool fInboundIn = false;

// Test that fFeeler is false by default.
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);

fInboundIn = true;
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit d934ffb

Please sign in to comment.