Browse Source

Merge branch 'danger' into duke

Conflicts:
	src/net.h
duke
Duke Leto 3 years ago
parent
commit
161750c807
  1. 21
      src/main.cpp
  2. 109
      src/net.cpp
  3. 11
      src/net.h
  4. 31
      src/test/netbase_tests.cpp

21
src/main.cpp

@ -6780,10 +6780,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true; return true;
} }
//fprintf(stderr,"netmsg: %s\n", strCommand.c_str()); fprintf(stderr,"%s: netmsg: %s from %s\n", __func__, strCommand.c_str(), pfrom->addr.ToString().c_str() );
if (strCommand == "version") {
// Feeler connections exist only to verify if node is online
if (pfrom->fFeeler) {
assert(pfrom->fInbound == false);
pfrom->fDisconnect = true;
fprintf(stderr,"%s: disconnecting feelerconn from %s\n", __func__, pfrom->addr.ToString().c_str() );
}
if (strCommand == "version")
{
// Each connection can only send one version message // Each connection can only send one version message
if (pfrom->nVersion != 0) if (pfrom->nVersion != 0)
{ {
@ -6896,15 +6902,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
} }
// Do Not Relay alerts
/*
{
LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom);
}
*/
pfrom->fSuccessfullyConnected = true; pfrom->fSuccessfullyConnected = true;
string remoteAddr; string remoteAddr;

109
src/net.cpp

@ -63,6 +63,9 @@ using namespace hush;
#endif #endif
#endif #endif
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
#define USE_TLS "encrypted as fuck" #define USE_TLS "encrypted as fuck"
#if defined(USE_TLS) && !defined(TLS1_3_VERSION) #if defined(USE_TLS) && !defined(TLS1_3_VERSION)
@ -74,9 +77,9 @@ using namespace hush;
using namespace std; using namespace std;
namespace { namespace {
//TODO: Make these CLI args int MAX_OUTBOUND_CONNECTIONS = GetArg("-maxoutboundconnections",64);
const int MAX_OUTBOUND_CONNECTIONS = 64; int MAX_FEELER_CONNECTIONS = GetArg("-maxfeelerconnections",1);
const int MAX_INBOUND_FROMIP = 3; int MAX_INBOUND_FROMIP = GetArg("-maxinboundfromip",3);
struct ListenSocket { struct ListenSocket {
SOCKET socket; SOCKET socket;
@ -1024,8 +1027,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
socklen_t len = sizeof(sockaddr); socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr; CAddress addr;
int nInbound = 0; int nInbound = 0;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
if (hSocket != INVALID_SOCKET) if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@ -1413,6 +1416,11 @@ void static ProcessOneShot()
} }
} }
int64_t PoissonNextSend(int64_t now, int average_interval_seconds)
{
return now + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
void ThreadOpenConnections() void ThreadOpenConnections()
{ {
// Connect to specific addresses // Connect to specific addresses
@ -1438,8 +1446,11 @@ void ThreadOpenConnections()
// Initiate network connections // Initiate network connections
int64_t nStart = GetTime(); int64_t nStart = GetTime();
while (true)
{ // Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true) {
ProcessOneShot(); ProcessOneShot();
MilliSleep(500); MilliSleep(500);
@ -1452,19 +1463,17 @@ void ThreadOpenConnections()
if (GetTime() - nStart > 60) { if (GetTime() - nStart > 60) {
static bool done = false; static bool done = false;
if (!done) { if (!done) {
// skip DNS seeds for staked chains.
LogPrintf("Adding fixed seed nodes.\n"); LogPrintf("Adding fixed seed nodes.\n");
addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1"));
done = true; done = true;
} }
} }
// Choose an address to connect to based on most recently seen // Choose an address to connect to based on most recently seen
CAddress addrConnect; CAddress addrConnect;
// Only connect out to one peer per network group (/16 for IPv4). // Only connect out to one peer per network group. Originally /16 for IPv4, now ASNs via
// Use -asmap for ASN bucketing // -asmap for ASN bucketing, which is enabled by default
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect. // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0; int nOutbound = 0;
set<vector<unsigned char> > setConnected; set<vector<unsigned char> > setConnected;
@ -1477,20 +1486,46 @@ void ThreadOpenConnections()
} }
} }
} }
assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));
// "Feeler Connections" as per https://eprint.iacr.org/2015/263.pdf
// "Eclipse Attacks on Bitcoin’s Peer-to-Peer Network" by
// Ethan Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg.
//
// 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.
// * Make feeler connections randomly with 120s average interval via PoissonNextSend.
// Originally from https://github.com/bitcoin/bitcoin/pull/8282
// Modified for API changes by Duke Leto
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 nNow = GetTime();
int nTries = 0;
addrman.ResolveCollisions(); addrman.ResolveCollisions();
int64_t nANow = GetTime();
int nTries = 0;
while (true) { while (true) {
CAddrInfo addr = addrman.SelectTriedCollision(); CAddrInfo addr = addrman.SelectTriedCollision();
// SelectTriedCollision returns an invalid address if it is empty. // SelectTriedCollision returns an invalid address if it is empty.
/* TODO: Uncomment when merged with feeler connections
if (!fFeeler || !addr.IsValid()) { if (!fFeeler || !addr.IsValid()) {
addr = addrman.Select(fFeeler); addr = addrman.Select(fFeeler);
} }
*/
// if we selected an invalid address, restart // if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup(addrman.m_asmap)) || IsLocal(addr)) if (!addr.IsValid() || setConnected.count(addr.GetGroup(addrman.m_asmap)) || IsLocal(addr))
@ -1507,9 +1542,16 @@ void ThreadOpenConnections()
continue; continue;
// only consider very recently tried nodes after 30 failed attempts // only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30) if (nNow - addr.nLastTry < 600 && nTries < 30)
continue; continue;
/* TODO: port this code
// only consider nodes missing relevant services after 40 failed attempts
if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
continue;
*/
//TODO: why is this a good thing?
// do not allow non-default ports, unless after 50 invalid addresses selected already // do not allow non-default ports, unless after 50 invalid addresses selected already
if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50)
continue; continue;
@ -1518,8 +1560,18 @@ void ThreadOpenConnections()
break; break;
} }
if (addrConnect.IsValid()) if (addrConnect.IsValid()) {
OpenNetworkConnection(addrConnect, &grant); 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().c_str());
printf("%s: Making feeler connection to %s\n", __func__, addrConnect.ToString().c_str());
}
//int failures = setConnected.size() >= std::min(nMaxConnections - 1, 2);
OpenNetworkConnection(addrConnect,/*failures,*/ &grant, NULL, false, fFeeler);
}
} }
} }
@ -1600,7 +1652,7 @@ void ThreadOpenAddedConnections()
} }
// if successful, this moves the passed grant to the constructed node // 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, /* bool fCountFailure, */ CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{ {
// Initiate outbound network connection // Initiate outbound network connection
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@ -1613,6 +1665,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
return false; return false;
CNode* pnode = ConnectNode(addrConnect, pszDest); CNode* pnode = ConnectNode(addrConnect, pszDest);
//CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
if (!pnode) if (!pnode)
@ -1620,8 +1673,11 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
if (grantOutbound) if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound); grantOutbound->MoveTo(pnode->grantOutbound);
pnode->fNetworkNode = true; pnode->fNetworkNode = true;
if (fOneShot) if (fOneShot)
pnode->fOneShot = true; pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;
return true; return true;
} }
@ -1867,7 +1923,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (semOutbound == NULL) { if (semOutbound == NULL) {
// initialize semaphore // initialize semaphore
int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); int nMaxOutbound = min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound); semOutbound = new CSemaphore(nMaxOutbound);
} }
@ -1916,7 +1972,7 @@ bool StopNode()
{ {
LogPrintf("StopNode()\n"); LogPrintf("StopNode()\n");
if (semOutbound) 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(); semOutbound->post();
if (HUSH_NSPV_FULLNODE && fAddressesInitialized) if (HUSH_NSPV_FULLNODE && fAddressesInitialized)
@ -2186,12 +2242,13 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nTimeOffset = 0; nTimeOffset = 0;
addr = addrIn; addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0; nVersion = 0;
strSubVer = ""; strSubVer = "";
fAllowlisted = false; fAllowlisted = false;
fOneShot = false; fOneShot = false;
fClient = false; // set by version message fClient = false; // set by version message
fInbound = fInboundIn; fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = false; fNetworkNode = false;
fSuccessfullyConnected = false; fSuccessfullyConnected = false;
fDisconnect = false; fDisconnect = false;

11
src/net.h

@ -82,10 +82,13 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 384; static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 384;
/** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */ /** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */
static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3; static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3;
/** Run the feeler connection loop once every 120 seconds. **/
static const int FEELER_INTERVAL = 120;
unsigned int ReceiveFloodSize(); unsigned int ReceiveFloodSize();
unsigned int SendBufferSize(); unsigned int SendBufferSize();
int64_t PoissonNextSend(int64_t now, int average_interval_seconds);
void AddOneShot(const std::string& strDest); void AddOneShot(const std::string& strDest);
void AddressCurrentlyConnected(const CService& addr); void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CNetAddr& ip);
@ -93,7 +96,7 @@ CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName); CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip); CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL); CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
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);
unsigned short GetListenPort(); unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fAllowlisted = false); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fAllowlisted = false);
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler); void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
@ -220,7 +223,8 @@ public:
int nStartingHeight; int nStartingHeight;
uint64_t nSendBytes; uint64_t nSendBytes;
uint64_t nRecvBytes; uint64_t nRecvBytes;
bool fAllowlisted; bool fAllowlisted; // If true this node bypasses DoS ban limits
bool fFeeler; // If true this node is being used as a short lived feeler.
double dPingTime; double dPingTime;
double dPingWait; double dPingWait;
std::string addrLocal; std::string addrLocal;
@ -228,7 +232,7 @@ public:
CAddress addr; CAddress addr;
// Bind address of our side of the connection // Bind address of our side of the connection
// CAddress addrBind; // https://github.com/bitcoin/bitcoin/commit/a7e3c2814c8e49197889a4679461be42254e5c51 // CAddress addrBind; // https://github.com/bitcoin/bitcoin/commit/a7e3c2814c8e49197889a4679461be42254e5c51
uint32_t m_mapped_as; uint32_t m_mapped_as; // Mapped ASN for this address
}; };
@ -319,6 +323,7 @@ public:
bool fOneShot; bool fOneShot;
bool fClient; bool fClient;
bool fInbound; bool fInbound;
bool fFeeler;
bool fNetworkNode; bool fNetworkNode;
bool fSuccessfullyConnected; bool fSuccessfullyConnected;
bool fDisconnect; bool fDisconnect;

31
src/test/netbase_tests.cpp

@ -5,9 +5,7 @@
#include "netbase.h" #include "netbase.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include <string> #include <string>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
@ -24,6 +22,35 @@ BOOST_AUTO_TEST_CASE(netbase_networks)
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION); BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION);
} }
/* TODO: port this feeler test
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_CASE(netbase_properties) BOOST_AUTO_TEST_CASE(netbase_properties)
{ {
BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4()); BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());

Loading…
Cancel
Save