aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlangerhans <[email protected]>2015-07-02 19:54:14 +0200
committerlangerhans <[email protected]>2015-07-02 19:54:14 +0200
commit66eb58e86c04432d0ef218e0df9d6b28e0ea5904 (patch)
treef96a918113239134511c06153cd87b50f1c23776
parentMerge branch '1.8.2-dev' into 1.8-maint (diff)
parentMerge pull request #1191 from langerhans/1.8.3-releaseprep (diff)
downloaddiscoin-66eb58e86c04432d0ef218e0df9d6b28e0ea5904.tar.xz
discoin-66eb58e86c04432d0ef218e0df9d6b28e0ea5904.zip
Merge branch '1.8.3-dev' into 1.8-maint
-rw-r--r--RELEASE_NOTES_1.8.3.md24
-rw-r--r--configure.ac4
-rw-r--r--doc/release-notes/RELEASE_NOTES_1.8.2.md (renamed from RELEASE_NOTES_1.8.2.md)0
-rwxr-xr-xqa/pull-tester/run-bitcoind-for-test.sh.in2
-rw-r--r--src/addrman.cpp326
-rw-r--r--src/addrman.h446
-rw-r--r--src/chainparams.cpp137
-rw-r--r--src/clientversion.h2
-rw-r--r--src/compat.h15
-rw-r--r--src/init.cpp61
-rw-r--r--src/main.cpp62
-rw-r--r--src/net.cpp212
-rw-r--r--src/net.h37
-rw-r--r--src/netbase.cpp173
-rw-r--r--src/netbase.h8
-rw-r--r--src/qt/forms/optionsdialog.ui20
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/optionsmodel.cpp28
-rw-r--r--src/qt/paymentserver.cpp14
-rw-r--r--src/rpcmisc.cpp2
-rw-r--r--src/rpcnet.cpp6
-rw-r--r--src/serialize.h29
-rw-r--r--src/util.cpp1
-rw-r--r--src/util.h1
24 files changed, 823 insertions, 795 deletions
diff --git a/RELEASE_NOTES_1.8.3.md b/RELEASE_NOTES_1.8.3.md
new file mode 100644
index 000000000..269918696
--- /dev/null
+++ b/RELEASE_NOTES_1.8.3.md
@@ -0,0 +1,24 @@
+# Dogecoin Core 1.8.3
+
+Dogecoin Core 1.8.3 is a security release. It fixes issues in regards to an upcoming announcement of possible DoS vulnerabilities.
+See [the announcement on the bitcoin-dev mailing list](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/009135.html) for reference.
+It is strongly recommended to upgrade your installation in case you run a node open to inbound connections from the internet.
+If your installation is not open to incoming connections this update is not mandatory, but we still recommend keeping your client up to date.
+
+## Dogecoin Core Release Notes
+
+* Pull in patches from usptream to mitigate the risk of a DoS attack.
+* Update the DNS seeds for more reliable bootstrapping of the initial peer discovery.
+* Update the list of fixed nodes, in case all other means of peer discovery fail.
+
+## Credits
+
+Listed in strictly alphabetical order, using name listed in Github. This
+includes those whose contributions to Bitcoin Core have been merged
+into this Dogecoin Core release:
+
+* P. Kaufmann
+* Max K.
+* Ross Nicoll
+* Wladimir J. van der Laan
+* Pieter Wuille
diff --git a/configure.ac b/configure.ac
index ae8797940..be9469e4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 8)
-define(_CLIENT_VERSION_REVISION, 2)
+define(_CLIENT_VERSION_REVISION, 3)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
-define(_COPYRIGHT_YEAR, 2014)
+define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Dogecoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[[email protected]],[dogecoin])
AC_CONFIG_AUX_DIR([src/build-aux])
AC_CONFIG_MACRO_DIR([src/m4])
diff --git a/RELEASE_NOTES_1.8.2.md b/doc/release-notes/RELEASE_NOTES_1.8.2.md
index 7e4f5d090..7e4f5d090 100644
--- a/RELEASE_NOTES_1.8.2.md
+++ b/doc/release-notes/RELEASE_NOTES_1.8.2.md
diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in
index 391046ab8..ecc42e12b 100755
--- a/qa/pull-tester/run-bitcoind-for-test.sh.in
+++ b/qa/pull-tester/run-bitcoind-for-test.sh.in
@@ -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.
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 3628af2ea..ac1250faa 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -9,34 +9,27 @@
using namespace std;
-int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
+int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
- CDataStream ss1(SER_GETHASH, 0);
- std::vector<unsigned char> vchKey = GetKey();
- ss1 << nKey << vchKey;
- uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64();
-
- CDataStream ss2(SER_GETHASH, 0);
- std::vector<unsigned char> vchGroupKey = GetGroup();
- ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
- uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64();
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetLow64();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetLow64();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
-int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
+int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const
{
- CDataStream ss1(SER_GETHASH, 0);
- std::vector<unsigned char> vchGroupKey = GetGroup();
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
- ss1 << nKey << vchGroupKey << vchSourceGroupKey;
- uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64();
-
- CDataStream ss2(SER_GETHASH, 0);
- ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
- uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64();
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetHash().GetLow64();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetLow64();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
+int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
+{
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetLow64();
+ return hash1 % ADDRMAN_BUCKET_SIZE;
+}
+
bool CAddrInfo::IsTerrible(int64_t nNow) const
{
if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute
@@ -67,8 +60,6 @@ double CAddrInfo::GetChance(int64_t nNow) const
if (nSinceLastSeen < 0) nSinceLastSeen = 0;
if (nSinceLastTry < 0) nSinceLastTry = 0;
- fChance *= 600.0 / (600.0 + nSinceLastSeen);
-
// deprioritize very recent attempts away
if (nSinceLastTry < 60*10)
fChance *= 0.01;
@@ -125,93 +116,44 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
vRandom[nRndPos2] = nId1;
}
-int CAddrMan::SelectTried(int nKBucket)
+void CAddrMan::Delete(int nId)
{
- std::vector<int> &vTried = vvTried[nKBucket];
-
- // random shuffle the first few elements (using the entire list)
- // find the least recently tried among them
- int64_t nOldest = -1;
- int nOldestPos = -1;
- for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++)
- {
- int nPos = GetRandInt(vTried.size() - i) + i;
- int nTemp = vTried[nPos];
- vTried[nPos] = vTried[i];
- vTried[i] = nTemp;
- assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
- if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
- nOldest = nTemp;
- nOldestPos = nPos;
- }
- }
+ assert(mapInfo.count(nId) != 0);
+ CAddrInfo& info = mapInfo[nId];
+ assert(!info.fInTried);
+ assert(info.nRefCount == 0);
- return nOldestPos;
+ SwapRandom(info.nRandomPos, vRandom.size() - 1);
+ vRandom.pop_back();
+ mapAddr.erase(info);
+ mapInfo.erase(nId);
+ nNew--;
}
-int CAddrMan::ShrinkNew(int nUBucket)
+void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
{
- assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
- std::set<int> &vNew = vvNew[nUBucket];
-
- // first look for deletable items
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
- {
- assert(mapInfo.count(*it));
- CAddrInfo &info = mapInfo[*it];
- if (info.IsTerrible())
- {
- if (--info.nRefCount == 0)
- {
- SwapRandom(info.nRandomPos, vRandom.size()-1);
- vRandom.pop_back();
- mapAddr.erase(info);
- mapInfo.erase(*it);
- nNew--;
- }
- vNew.erase(it);
- return 0;
+ // if there is an entry in the specified bucket, delete it.
+ if (vvNew[nUBucket][nUBucketPos] != -1) {
+ int nIdDelete = vvNew[nUBucket][nUBucketPos];
+ CAddrInfo& infoDelete = mapInfo[nIdDelete];
+ assert(infoDelete.nRefCount > 0);
+ infoDelete.nRefCount--;
+ vvNew[nUBucket][nUBucketPos] = -1;
+ if (infoDelete.nRefCount == 0) {
+ Delete(nIdDelete);
}
}
-
- // otherwise, select four randomly, and pick the oldest of those to replace
- int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())};
- int nI = 0;
- int nOldest = -1;
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
- {
- if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
- {
- assert(nOldest == -1 || mapInfo.count(*it) == 1);
- if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
- nOldest = *it;
- }
- nI++;
- }
- assert(mapInfo.count(nOldest) == 1);
- CAddrInfo &info = mapInfo[nOldest];
- if (--info.nRefCount == 0)
- {
- SwapRandom(info.nRandomPos, vRandom.size()-1);
- vRandom.pop_back();
- mapAddr.erase(info);
- mapInfo.erase(nOldest);
- nNew--;
- }
- vNew.erase(nOldest);
-
- return 1;
}
-void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
+void CAddrMan::MakeTried(CAddrInfo& info, int nId)
{
- assert(vvNew[nOrigin].count(nId) == 1);
-
// remove the entry from all new buckets
- for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
- {
- if ((*it).erase(nId))
+ for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ int pos = info.GetBucketPosition(nKey, true, bucket);
+ if (vvNew[bucket][pos] == nId) {
+ vvNew[bucket][pos] = -1;
info.nRefCount--;
+ }
}
nNew--;
@@ -219,46 +161,36 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
// what tried bucket to move the entry to
int nKBucket = info.GetTriedBucket(nKey);
- std::vector<int> &vTried = vvTried[nKBucket];
-
- // first check whether there is place to just add it
- if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
- {
- vTried.push_back(nId);
- nTried++;
- info.fInTried = true;
- return;
- }
-
- // otherwise, find an item to evict
- int nPos = SelectTried(nKBucket);
-
- // find which new bucket it belongs to
- assert(mapInfo.count(vTried[nPos]) == 1);
- int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
- std::set<int> &vNew = vvNew[nUBucket];
-
- // remove the to-be-replaced tried entry from the tried set
- CAddrInfo& infoOld = mapInfo[vTried[nPos]];
- infoOld.fInTried = false;
- infoOld.nRefCount = 1;
- // do not update nTried, as we are going to move something else there immediately
-
- // check whether there is place in that one,
- if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE)
- {
- // if so, move it back there
- vNew.insert(vTried[nPos]);
- } else {
- // otherwise, move it to the new bucket nId came from (there is certainly place there)
- vvNew[nOrigin].insert(vTried[nPos]);
+ int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
+
+ // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
+ if (vvTried[nKBucket][nKBucketPos] != -1) {
+ // find an item to evict
+ int nIdEvict = vvTried[nKBucket][nKBucketPos];
+ assert(mapInfo.count(nIdEvict) == 1);
+ CAddrInfo& infoOld = mapInfo[nIdEvict];
+
+ // Remove the to-be-evicted item from the tried set.
+ infoOld.fInTried = false;
+ vvTried[nKBucket][nKBucketPos] = -1;
+ nTried--;
+
+ // find which new bucket it belongs to
+ int nUBucket = infoOld.GetNewBucket(nKey);
+ int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
+ ClearNew(nUBucket, nUBucketPos);
+ assert(vvNew[nUBucket][nUBucketPos] == -1);
+
+ // Enter it into the new set again.
+ infoOld.nRefCount = 1;
+ vvNew[nUBucket][nUBucketPos] = nIdEvict;
+ nNew++;
}
- nNew++;
+ assert(vvTried[nKBucket][nKBucketPos] == -1);
- vTried[nPos] = nId;
- // we just overwrote an entry in vTried; no need to update nTried
+ vvTried[nKBucket][nKBucketPos] = nId;
+ nTried++;
info.fInTried = true;
- return;
}
void CAddrMan::Good_(const CService &addr, int64_t nTime)
@@ -279,22 +211,21 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
// update info
info.nLastSuccess = nTime;
info.nLastTry = nTime;
- info.nTime = nTime;
info.nAttempts = 0;
+ // nTime is not updated here, to avoid leaking information about
+ // currently-connected peers.
// if it is already in the tried set, don't do anything else
if (info.fInTried)
return;
// find a bucket it is in now
- int nRnd = GetRandInt(vvNew.size());
+ int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucket = -1;
- for (unsigned int n = 0; n < vvNew.size(); n++)
- {
- int nB = (n+nRnd) % vvNew.size();
- std::set<int> &vNew = vvNew[nB];
- if (vNew.count(nId))
- {
+ for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
+ int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
+ int nBpos = info.GetBucketPosition(nKey, true, nB);
+ if (vvNew[nB][nBpos] == nId) {
nUBucket = nB;
break;
}
@@ -307,7 +238,7 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
// move nId to the tried tables
- MakeTried(info, nId, nUBucket);
+ MakeTried(info, nId);
}
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty)
@@ -356,13 +287,25 @@ bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimeP
}
int nUBucket = pinfo->GetNewBucket(nKey, source);
- std::set<int> &vNew = vvNew[nUBucket];
- if (!vNew.count(nId))
- {
- pinfo->nRefCount++;
- if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
- ShrinkNew(nUBucket);
- vvNew[nUBucket].insert(nId);
+ int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
+ if (vvNew[nUBucket][nUBucketPos] != nId) {
+ bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
+ if (!fInsert) {
+ CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
+ if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
+ // Overwrite the existing new table entry.
+ fInsert = true;
+ }
+ }
+ if (fInsert) {
+ ClearNew(nUBucket, nUBucketPos);
+ pinfo->nRefCount++;
+ vvNew[nUBucket][nUBucketPos] = nId;
+ } else {
+ if (pinfo->nRefCount == 0) {
+ Delete(nId);
+ }
+ }
}
return fNew;
}
@@ -386,44 +329,39 @@ void CAddrMan::Attempt_(const CService &addr, int64_t nTime)
info.nAttempts++;
}
-CAddress CAddrMan::Select_(int nUnkBias)
+CAddress CAddrMan::Select_()
{
if (size() == 0)
return CAddress();
- double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
- double nCorNew = sqrt(nNew) * nUnkBias;
- if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried)
- {
+ // Use a 50% chance for choosing between tried and new table entries.
+ if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) {
// use a tried node
double fChanceFactor = 1.0;
- while(1)
- {
- int nKBucket = GetRandInt(vvTried.size());
- std::vector<int> &vTried = vvTried[nKBucket];
- if (vTried.size() == 0) continue;
- int nPos = GetRandInt(vTried.size());
- assert(mapInfo.count(vTried[nPos]) == 1);
- CAddrInfo &info = mapInfo[vTried[nPos]];
- if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
+ while (1) {
+ int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT);
+ int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
+ if (vvTried[nKBucket][nKBucketPos] == -1)
+ continue;
+ int nId = vvTried[nKBucket][nKBucketPos];
+ assert(mapInfo.count(nId) == 1);
+ CAddrInfo& info = mapInfo[nId];
+ if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
}
} else {
// use a new node
double fChanceFactor = 1.0;
- while(1)
- {
- int nUBucket = GetRandInt(vvNew.size());
- std::set<int> &vNew = vvNew[nUBucket];
- if (vNew.size() == 0) continue;
- int nPos = GetRandInt(vNew.size());
- std::set<int>::iterator it = vNew.begin();
- while (nPos--)
- it++;
- assert(mapInfo.count(*it) == 1);
- CAddrInfo &info = mapInfo[*it];
- if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
+ while (1) {
+ int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
+ int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
+ if (vvNew[nUBucket][nUBucketPos] == -1)
+ continue;
+ int nId = vvNew[nUBucket][nUBucketPos];
+ assert(mapInfo.count(nId) == 1);
+ CAddrInfo& info = mapInfo[nId];
+ if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
}
@@ -462,29 +400,37 @@ int CAddrMan::Check_()
if (setTried.size() != nTried) return -9;
if (mapNew.size() != nNew) return -10;
- for (int n=0; n<vvTried.size(); n++)
- {
- std::vector<int> &vTried = vvTried[n];
- for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++)
- {
- if (!setTried.count(*it)) return -11;
- setTried.erase(*it);
+ for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvTried[n][i] != -1) {
+ if (!setTried.count(vvTried[n][i]))
+ return -11;
+ if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n)
+ return -17;
+ if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
+ return -18;
+ setTried.erase(vvTried[n][i]);
+ }
}
}
- for (int n=0; n<vvNew.size(); n++)
- {
- std::set<int> &vNew = vvNew[n];
- for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
- {
- if (!mapNew.count(*it)) return -12;
- if (--mapNew[*it] == 0)
- mapNew.erase(*it);
+ for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[n][i] != -1) {
+ if (!mapNew.count(vvNew[n][i]))
+ return -12;
+ if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
+ return -19;
+ if (--mapNew[vvNew[n][i]] == 0)
+ mapNew.erase(vvNew[n][i]);
+ }
}
}
if (setTried.size()) return -13;
if (mapNew.size()) return -15;
+ if (nKey.IsNull())
+ return -16;
return 0;
}
diff --git a/src/addrman.h b/src/addrman.h
index e2b0cb109..916f4da4b 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -8,6 +8,7 @@
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
+#include "uint256.h"
#include "util.h"
#include <map>
@@ -75,17 +76,20 @@ public:
}
// Calculate in which "tried" bucket this entry belongs
- int GetTriedBucket(const std::vector<unsigned char> &nKey) const;
+ int GetTriedBucket(const uint256 &nKey) const;
// Calculate in which "new" bucket this entry belongs, given a certain source
- int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const;
+ int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const;
// Calculate in which "new" bucket this entry belongs, using its default source
- int GetNewBucket(const std::vector<unsigned char> &nKey) const
+ int GetNewBucket(const uint256 &nKey) const
{
return GetNewBucket(nKey, source);
}
+ //! Calculate in which position of a bucket to store this entry.
+ int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
+
// Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
@@ -94,55 +98,49 @@ public:
};
-// Stochastic address manager
-//
-// Design goals:
-// * Only keep a limited number of addresses around, so that addr.dat and memory requirements do not grow without bound.
-// * Keep the address tables in-memory, and asynchronously dump the entire to able in addr.dat.
-// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
-//
-// To that end:
-// * Addresses are organized into buckets.
-// * Address that have not yet been tried go into 256 "new" buckets.
-// * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random
-// * The actual bucket is chosen from one of these, based on the range the address itself is located.
-// * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that
-// are seen frequently. The chance for increasing this multiplicity decreases exponentially.
-// * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
-// ones) is removed from it first.
-// * Addresses of nodes that are known to be accessible go into 64 "tried" buckets.
-// * Each address range selects at random 4 of these buckets.
-// * The actual bucket is chosen from one of these, based on the full address.
-// * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
-// tried ones) is evicted from it, back to the "new" buckets.
-// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
-// be observable by adversaries.
-// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
-// consistency checks for the entire data structure.
+/** Stochastic address manager
+ *
+ * Design goals:
+ * * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat.
+ * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
+ *
+ * To that end:
+ * * Addresses are organized into buckets.
+ * * Address that have not yet been tried go into 1024 "new" buckets.
+ * * Based on the address range (/16 for IPv4) of source of the information, 64 buckets are selected at random
+ * * The actual bucket is chosen from one of these, based on the range the address itself is located.
+ * * One single address can occur in up to 8 different buckets, to increase selection chances for addresses that
+ * are seen frequently. The chance for increasing this multiplicity decreases exponentially.
+ * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
+ * ones) is removed from it first.
+ * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
+ * * Each address range selects at random 8 of these buckets.
+ * * The actual bucket is chosen from one of these, based on the full address.
+ * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
+ * tried ones) is evicted from it, back to the "new" buckets.
+ * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
+ * be observable by adversaries.
+ * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
+ * consistency checks for the entire data structure.
+ */
// total number of buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_COUNT 64
-
-// maximum allowed number of entries in buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_SIZE 64
+#define ADDRMAN_TRIED_BUCKET_COUNT 256
// total number of buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_COUNT 256
+#define ADDRMAN_NEW_BUCKET_COUNT 1024
-// maximum allowed number of entries in buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_SIZE 64
+// maximum allowed number of entries in buckets for new and tried addresses
+#define ADDRMAN_BUCKET_SIZE 64
// over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
-#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4
+#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
// over how many buckets entries with new addresses originating from a single group are spread
-#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32
+#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
// in how many buckets for entries with new addresses a single address may occur
-#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4
-
-// how many entries in a bucket with tried addresses are inspected, when selecting one to replace
-#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4
+#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
// how old addresses can maximally be
#define ADDRMAN_HORIZON_DAYS 30
@@ -170,7 +168,7 @@ private:
mutable CCriticalSection cs;
// secret key to randomize bucket select with
- std::vector<unsigned char> nKey;
+ uint256 nKey;
// last used nId
int nIdCount;
@@ -188,13 +186,13 @@ private:
int nTried;
// list of "tried" buckets
- std::vector<std::vector<int> > vvTried;
+ int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
// number of (unique) "new" entries
int nNew;
// list of "new" buckets
- std::vector<std::set<int> > vvNew;
+ int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
protected:
@@ -208,17 +206,14 @@ protected:
// Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
- // Return position in given bucket to replace.
- int SelectTried(int nKBucket);
+ // Move an entry from the "new" table(s) to the "tried" table
+ void MakeTried(CAddrInfo& info, int nId);
- // Remove an element from a "new" bucket.
- // This is the only place where actual deletes occur.
- // They are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
- int ShrinkNew(int nUBucket);
+ // Delete an entry. It must not be in tried, and have refcount 0.
+ void Delete(int nId);
- // Move an entry from the "new" table(s) to the "tried" table
- // @pre vvUnkown[nOrigin].count(nId) != 0
- void MakeTried(CAddrInfo& info, int nId, int nOrigin);
+ // Clear a position in a "new" table. This is the only place where entries are actually deleted.
+ void ClearNew(int nUBucket, int nUBucketPos);
// Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64_t nTime);
@@ -230,8 +225,7 @@ protected:
void Attempt_(const CService &addr, int64_t nTime);
// Select an address to connect to.
- // nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
- CAddress Select_(int nUnkBias);
+ CAddress Select_();
#ifdef DEBUG_ADDRMAN
// Perform consistency check. Returns an error code or zero.
@@ -245,153 +239,220 @@ protected:
void Connected_(const CService &addr, int64_t nTime);
public:
-
- IMPLEMENT_SERIALIZE
- (({
- // serialized format:
- // * version byte (currently 0)
- // * nKey
- // * nNew
- // * nTried
- // * number of "new" buckets
- // * all nNew addrinfos in vvNew
- // * all nTried addrinfos in vvTried
- // * for each bucket:
- // * number of elements
- // * for each element: index
- //
- // Notice that vvTried, mapAddr and vVector are never encoded explicitly;
- // they are instead reconstructed from the other information.
- //
- // vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
- // otherwise it is reconstructed as well.
- //
- // This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
- // changes to the ADDRMAN_ parameters without breaking the on-disk structure.
- {
- LOCK(cs);
- unsigned char nVersion = 0;
- READWRITE(nVersion);
- READWRITE(nKey);
- READWRITE(nNew);
- READWRITE(nTried);
-
- CAddrMan *am = const_cast<CAddrMan*>(this);
- if (fWrite)
- {
- int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
- READWRITE(nUBuckets);
- std::map<int, int> mapUnkIds;
- int nIds = 0;
- for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
- {
- if (nIds == nNew) break; // this means nNew was wrong, oh ow
- mapUnkIds[(*it).first] = nIds;
- CAddrInfo &info = (*it).second;
- if (info.nRefCount)
- {
- READWRITE(info);
- nIds++;
- }
- }
- nIds = 0;
- for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
- {
- if (nIds == nTried) break; // this means nTried was wrong, oh ow
- CAddrInfo &info = (*it).second;
- if (info.fInTried)
- {
- READWRITE(info);
- nIds++;
- }
+ /**
+ * serialized format:
+ * * version byte (currently 1)
+ * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
+ * * nNew
+ * * nTried
+ * * number of "new" buckets XOR 2**30
+ * * all nNew addrinfos in vvNew
+ * * all nTried addrinfos in vvTried
+ * * for each bucket:
+ * * number of elements
+ * * for each element: index
+ *
+ * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
+ * as incompatible. This is necessary because it did not check the version number on
+ * deserialization.
+ *
+ * Notice that vvTried, mapAddr and vVector are never encoded explicitly;
+ * they are instead reconstructed from the other information.
+ *
+ * vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
+ * otherwise it is reconstructed as well.
+ *
+ * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
+ * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
+ *
+ * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
+ * very little in common.
+ */
+ template<typename Stream>
+ void Serialize(Stream &s, int nType, int nVersionDummy) const
+ {
+ LOCK(cs);
+
+ unsigned char nVersion = 1;
+ s << nVersion;
+ s << ((unsigned char)32);
+ s << nKey;
+ s << nNew;
+ s << nTried;
+
+ int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
+ s << nUBuckets;
+ std::map<int, int> mapUnkIds;
+ int nIds = 0;
+ for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
+ mapUnkIds[(*it).first] = nIds;
+ const CAddrInfo &info = (*it).second;
+ if (info.nRefCount) {
+ assert(nIds != nNew); // this means nNew was wrong, oh ow
+ s << info;
+ nIds++;
+ }
+ }
+ nIds = 0;
+ for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
+ const CAddrInfo &info = (*it).second;
+ if (info.fInTried) {
+ assert(nIds != nTried); // this means nTried was wrong, oh ow
+ s << info;
+ nIds++;
+ }
+ }
+ for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ int nSize = 0;
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[bucket][i] != -1)
+ nSize++;
+ }
+ s << nSize;
+ for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
+ if (vvNew[bucket][i] != -1) {
+ int nIndex = mapUnkIds[vvNew[bucket][i]];
+ s << nIndex;
}
- for (std::vector<std::set<int> >::iterator it = am->vvNew.begin(); it != am->vvNew.end(); it++)
- {
- const std::set<int> &vNew = (*it);
- int nSize = vNew.size();
- READWRITE(nSize);
- for (std::set<int>::iterator it2 = vNew.begin(); it2 != vNew.end(); it2++)
- {
- int nIndex = mapUnkIds[*it2];
- READWRITE(nIndex);
- }
+ }
+ }
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s, int nType, int nVersionDummy)
+ {
+ LOCK(cs);
+
+ Clear();
+
+ unsigned char nVersion;
+ s >> nVersion;
+ unsigned char nKeySize;
+ s >> nKeySize;
+ if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
+ s >> nKey;
+ s >> nNew;
+ s >> nTried;
+ int nUBuckets = 0;
+ s >> nUBuckets;
+ if (nVersion != 0) {
+ nUBuckets ^= (1 << 30);
+ }
+
+ // Deserialize entries from the new table.
+ for (int n = 0; n < nNew; n++) {
+ CAddrInfo &info = mapInfo[n];
+ s >> info;
+ mapAddr[info] = n;
+ info.nRandomPos = vRandom.size();
+ vRandom.push_back(n);
+ if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
+ // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
+ // immediately try to give them a reference based on their primary source address.
+ int nUBucket = info.GetNewBucket(nKey);
+ int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
+ if (vvNew[nUBucket][nUBucketPos] == -1) {
+ vvNew[nUBucket][nUBucketPos] = n;
+ info.nRefCount++;
}
+ }
+ }
+ nIdCount = nNew;
+
+ // Deserialize entries from the tried table.
+ int nLost = 0;
+ for (int n = 0; n < nTried; n++) {
+ CAddrInfo info;
+ s >> info;
+ int nKBucket = info.GetTriedBucket(nKey);
+ int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
+ if (vvTried[nKBucket][nKBucketPos] == -1) {
+ info.nRandomPos = vRandom.size();
+ info.fInTried = true;
+ vRandom.push_back(nIdCount);
+ mapInfo[nIdCount] = info;
+ mapAddr[info] = nIdCount;
+ vvTried[nKBucket][nKBucketPos] = nIdCount;
+ nIdCount++;
} else {
- int nUBuckets = 0;
- READWRITE(nUBuckets);
- am->nIdCount = 0;
- am->mapInfo.clear();
- am->mapAddr.clear();
- am->vRandom.clear();
- am->vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
- am->vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
- for (int n = 0; n < am->nNew; n++)
- {
- CAddrInfo &info = am->mapInfo[n];
- READWRITE(info);
- am->mapAddr[info] = n;
- info.nRandomPos = vRandom.size();
- am->vRandom.push_back(n);
- if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT)
- {
- am->vvNew[info.GetNewBucket(am->nKey)].insert(n);
+ nLost++;
+ }
+ }
+ nTried -= nLost;
+
+ // Deserialize positions in the new table (if possible).
+ for (int bucket = 0; bucket < nUBuckets; bucket++) {
+ int nSize = 0;
+ s >> nSize;
+ for (int n = 0; n < nSize; n++) {
+ int nIndex = 0;
+ s >> nIndex;
+ if (nIndex >= 0 && nIndex < nNew) {
+ CAddrInfo &info = mapInfo[nIndex];
+ int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
+ if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
info.nRefCount++;
+ vvNew[bucket][nUBucketPos] = nIndex;
}
}
- am->nIdCount = am->nNew;
- int nLost = 0;
- for (int n = 0; n < am->nTried; n++)
- {
- CAddrInfo info;
- READWRITE(info);
- std::vector<int> &vTried = am->vvTried[info.GetTriedBucket(am->nKey)];
- if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
- {
- info.nRandomPos = vRandom.size();
- info.fInTried = true;
- am->vRandom.push_back(am->nIdCount);
- am->mapInfo[am->nIdCount] = info;
- am->mapAddr[info] = am->nIdCount;
- vTried.push_back(am->nIdCount);
- am->nIdCount++;
- } else {
- nLost++;
- }
- }
- am->nTried -= nLost;
- for (int b = 0; b < nUBuckets; b++)
- {
- std::set<int> &vNew = am->vvNew[b];
- int nSize = 0;
- READWRITE(nSize);
- for (int n = 0; n < nSize; n++)
- {
- int nIndex = 0;
- READWRITE(nIndex);
- CAddrInfo &info = am->mapInfo[nIndex];
- if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
- {
- info.nRefCount++;
- vNew.insert(nIndex);
- }
- }
- }
}
}
- });)
- CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>())
+ // Prune new entries with refcount 0 (as a result of collisions).
+ int nLostUnk = 0;
+ for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
+ if (it->second.fInTried == false && it->second.nRefCount == 0) {
+ std::map<int, CAddrInfo>::const_iterator itCopy = it++;
+ Delete(itCopy->first);
+ nLostUnk++;
+ } else {
+ it++;
+ }
+ }
+ if (nLost + nLostUnk > 0) {
+ LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
+ }
+
+ Check();
+ }
+
+ unsigned int GetSerializeSize(int nType, int nVersion) const
{
- nKey.resize(32);
- RAND_bytes(&nKey[0], 32);
+ return (CSizeComputer(nType, nVersion) << *this).size();
+ }
+
+ void Clear()
+ {
+ std::vector<int>().swap(vRandom);
+ RAND_bytes((unsigned char *)&nKey, 32);
+ for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
+ for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
+ vvNew[bucket][entry] = -1;
+ }
+ }
+ for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
+ for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
+ vvTried[bucket][entry] = -1;
+ }
+ }
- nIdCount = 0;
- nTried = 0;
- nNew = 0;
+ nIdCount = 0;
+ nTried = 0;
+ nNew = 0;
+ }
+
+ CAddrMan()
+ {
+ Clear();
+ }
+
+ ~CAddrMan()
+ {
+ nKey = uint256(0);
}
// Return the number of (unique) addresses in all tables.
- int size()
+ int size()
{
return vRandom.size();
}
@@ -462,15 +523,16 @@ public:
}
}
- // Choose an address to connect to.
- // nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
- CAddress Select(int nUnkBias = 50)
+ /**
+ * Choose an address to connect to.
+ */
+ CAddress Select()
{
CAddress addrRet;
{
LOCK(cs);
Check();
- addrRet = Select_(nUnkBias);
+ addrRet = Select_();
Check();
}
return addrRet;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 57cd0afff..12dadddfa 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -22,81 +22,62 @@ using namespace boost::assign;
unsigned int pnSeed[] =
{
- 0xdc7fa218, 0xb4b68d18, 0xd286166c, 0xb0bbb052, 0x5d9fe2bc, 0x0256c0ad, 0x4297d23e, 0x2cf5226c,
- 0xa80dfb94, 0xf1a134d0, 0x4215042e, 0x7c51486d, 0x3a51486d, 0xd5c63832, 0xde5b7e02, 0xdb176018,
- 0x332745ad, 0x7172c7c6, 0xfb90b742, 0x134dd9a2, 0x25e238ae, 0xc332ed40, 0x24a0a4c6, 0xcd5e0905,
- 0xcaca87dc, 0xe28ac836, 0xc79c2942, 0x672baa6b, 0xa2012363, 0xf848f160, 0x34747b6d, 0xe6f7f1c0,
- 0xbbc51955, 0x4e106d5b, 0x69e47046, 0x4ca0d54a, 0x6d0a65c6, 0x441d9c32, 0x436d5d81, 0xbdfffbce,
- 0x1cd2f2a2, 0x112daa6b, 0x30b85f47, 0x02100ab9, 0x2e044bad, 0x2071ff45, 0x5f98b54b, 0x55a40905,
- 0x651aaa6b, 0xe99ef2c5, 0x17c35ad0, 0x8db55d41, 0x587921cb, 0x3865ea2e, 0xba0d63c0, 0x8eb88b52,
- 0x7a80a7c7, 0x4d5c5747, 0x3fd4f3a2, 0xf825be43, 0x161eaa6b, 0x43eda52e, 0x03b422b0, 0x5c0e63c0,
- 0x6dfc47d4, 0x1a017ebc, 0xfb65c7c6, 0x535809b0, 0x8b58f181, 0x2454ed5e, 0x68220254, 0x7aaca143,
- 0x91c10a55, 0x8bd74ece, 0xd67ef118, 0x0a15aa46, 0xa0c1b1ad, 0x4052d74a, 0xede8494b, 0xd5c49452,
- 0x8fc97e18, 0x78c01c54, 0x2fbcf1c0, 0x335a046c, 0x3dc8834b, 0x6c550025, 0x278ab5d1, 0xc4422e4e,
- 0x45e2073a, 0xa83fbd41, 0x738d1581, 0x9a3c0cc3, 0xf48d5436, 0x5ba835c6, 0xc63aaa6b, 0xd33328bc,
- 0x9f703ab0, 0xee45ba36, 0x78417244, 0xf9e6e460, 0x288eb06c, 0x22a3e417, 0xdade69c6, 0x8b7bc447,
- 0x7975c244, 0x51ef4cb7, 0x48ecffad, 0x32bf0918, 0xa98baa51, 0xedf5fa60, 0xe0aca658, 0x68fca0d9,
- 0xe762c7c6, 0x1d2bc24e, 0x612d454b, 0x759fd295, 0xc218ef17, 0xb5c0b162, 0x5aaed56c, 0x1b52dc62,
- 0x416c2d05, 0x42fbbfc3, 0xdc63134c, 0xc1b9e2bc, 0x0bd7f74d, 0x5eb9e2bc, 0xaf05a843, 0xafdf2e32,
- 0x7d35bdd5, 0x8feeaa6b, 0x3e9e7d18, 0x47d1079d, 0x4d1d6a57, 0xc6cbffad, 0x0e80a7c7, 0x8dd0e8d8,
- 0x334a066b, 0x31fae3bc, 0x0669e53a, 0x632c784c, 0x30381cb9, 0xaea5d118, 0xb7ee9ade, 0x4c37175e,
- 0x9885f3a2, 0xbde5f6d8, 0xae62f3a2, 0xe276692e, 0xba5d1218, 0x511d5618, 0x7e81d78f, 0x14eb4c90,
- 0x44e5c780, 0xe2708abc, 0xe261d3c6, 0x7aca584a, 0x8c037786, 0x7e3baa6b, 0xb912d8a2, 0x170763c0,
- 0xbed1d23e, 0xdce46ccf, 0x5cdb1748, 0xc215f5ac, 0x99f7cabc, 0x4d658248, 0x3798bacd, 0x2dbb8932,
- 0xe93faa6b, 0x639f534b, 0x43f6754c, 0x0440bd44, 0x4919aa6b, 0x30644aad, 0xc96e9c4e, 0x421daa6b,
- 0x90760248, 0x096a1bc6, 0xba4b40ad, 0x3574fa5b, 0x20fe0732, 0x41535143, 0xdf843944, 0x103b8dd1,
- 0xde76a032, 0xf405e447, 0xcc86bb25, 0xb3b22e6c, 0x12c35ad0, 0xa330aa6b, 0x14e69544, 0x177becd1,
- 0xf32e484b, 0x15b1ce6d, 0x0d2c7662, 0x862d6441, 0xa2c39805, 0xc7eeaa6b, 0xf38f494c, 0x16d5b947,
- 0x9fb8e2bc, 0xe13e175e, 0x656c39ad, 0x7a384946, 0x10460905, 0x9cf870d1, 0xb375c60e, 0x481cba6a,
- 0x87ed6cd8, 0x2d7b67ae, 0x01540f48, 0x84028fc6, 0xdd85c144, 0x8f53ee54, 0x1a9e4fad, 0x84acc548,
- 0x52d51248, 0xac47ab43, 0xf16ab743, 0x65ab6f18, 0xa8f73060, 0x56c84832, 0x9c6a604a, 0x8ef1ffad,
- 0x4676a043, 0x6568c23e, 0x416ed459, 0xb586ec62, 0x122e98c2, 0x81a65618, 0x17db048e, 0x690f3b25,
- 0xb58c4e32, 0x8e69e297, 0xd4dcaf42, 0x5158ac43, 0x0f9da082, 0x6cbaee60, 0x9e115b82, 0x55dffe96,
- 0xa899f660, 0x846a0905, 0xf53a9252, 0xb283a4b8, 0x6db66b18, 0x867316b2, 0xdfad5753, 0x59995dd0,
- 0x5e1caa6b, 0x08b3f160, 0x056a1bc6, 0x9c5403ae, 0x738cae43, 0x77fd211b, 0xd8e3a951, 0x150aad43,
- 0x558809b0, 0xf04f454a, 0x09daf150, 0x3a433d63, 0xa4daf1c0, 0x4d551ac7, 0xd0edec69, 0xbe36f118,
- 0x5b76b818, 0x8d919bd8, 0xbc92ea52, 0xe8096ec3, 0x1895e2bc, 0xfd053360, 0x701c42ad, 0x9a8e9bd8,
- 0xac06aa6b, 0xc9851a56, 0x54f65e46, 0xb39e306c, 0x880763c0, 0x361f1fb0, 0x95a5b04c, 0x897319ad,
- 0xc1b9be46, 0xe6d89d9d, 0xa75cd443, 0xb7361147, 0x630b8b25, 0x5a2e4ea6, 0x203bbb4b, 0x5b4b6c18,
- 0x9dbbac43, 0x6d0663c0, 0x1f115536, 0x61d80718, 0xf4fde097, 0xfb50e162, 0x954a6276, 0x0006ee47,
- 0x30b26eae, 0xf5737358, 0xf9a5fdce, 0xf2c75d18, 0xfda64b25, 0xd565d1a2, 0xf055a743, 0x10aaa545,
- 0xa70c63c0, 0xa15a4450, 0xdbcb13ad, 0xdc705246, 0x02f7e9c7, 0xe57e6763, 0x65604ead, 0x07df1955,
- 0x882faa6b, 0xb4286b18, 0x539747c0, 0xc9b6a1c0, 0xb76e7f46, 0xf3418432, 0xd5bbb153, 0xb840d3a2,
- 0x6c0717d9, 0xb14109b0, 0x94076181, 0xf40aa953, 0x08de89c3, 0x06bdaa4d, 0x27efae32, 0x5ba4fe45,
- 0x1e7410cc, 0x57e847d4, 0xe5425177, 0xb50b714c, 0x06513532, 0xfde617c6, 0xe05c3532, 0x0af30852,
- 0xa2a33a60, 0x2cc7f3a2, 0x5777cf57, 0x313477d5, 0x311544c1, 0x49f4aa6b, 0xef01ef17, 0x07db33d4,
- 0x0a60c947, 0xe4174e4d, 0x34058a12, 0x411e3ab8, 0xfc4a9532, 0x5bcaf082, 0x55c21955, 0x489a32b6,
- 0xf1f7154c, 0x60fa9f6e, 0x4dc4ec57, 0x5fe7a743, 0x1309e552, 0x03e12c42, 0x07f4175e, 0xcb56aa43,
- 0x9d411787, 0xc1686041, 0xeec21955, 0xe97cf3a2, 0x11cc6044, 0xce9b2b47, 0x32bb53d4, 0xc7153b25,
- 0x7c24188d, 0x1640c947, 0x1606b941, 0x671d864b, 0xb4430118, 0x3c6641ad, 0xf99000c0, 0x57a745ad,
- 0xf098880e, 0x7cd14298, 0xb53316b2, 0x5b0749ae, 0x80c734c6, 0x5bb26318, 0xf5734761, 0xb5a0f1c0,
- 0x643f3cae, 0xd034324a, 0xd5ef81ae, 0xa383e447, 0x8c820298, 0xeba139ae, 0x1e73c80e, 0x0c3fe743,
- 0x8ac65918, 0x03104081, 0xa486bb25, 0x24165343, 0x15c67118, 0x6204f948, 0x4e3d5bc6, 0x3ef9f382,
- 0xe3e7524a, 0x9f10634c, 0xfba8794c, 0x0c2d306c, 0xb99df762, 0x3e1a4d47, 0x3f6c3951, 0xd373354d,
- 0xca206c4a, 0x6f454aad, 0x02f5af43, 0x0f35831f, 0x31bcd4ad, 0xfa34da48, 0x3a598cae, 0x26ef7f4c,
- 0xa104b648, 0x9cf2134c, 0xc5c2336c, 0x448f9c5b, 0x55b8f1c0, 0x115917ad, 0x33216f4b, 0x5c67692e,
- 0xd436c658, 0x7c22da36, 0x0ce9e217, 0xa62a3160, 0xb08803ae, 0xf918c162, 0x0e9c096c, 0xf250119c,
- 0x0d987f47, 0x40254832, 0x610df245, 0xa55cf3a2, 0xd4886e4a, 0xc172aa43, 0x1af4c04e, 0xbe2d47ae,
- 0x58a0cf45, 0xa414dc48, 0xdde3f3a2, 0x26562843, 0x9aea0455, 0xb1b63c44, 0xcef89963, 0x12005d4d,
- 0x21c21754, 0x18eef160, 0x4903a1cf, 0x9b023818, 0x4685336c, 0xc9f31556, 0xe6dd0a18, 0x099630ad,
- 0x10dabd32, 0xcaaf708c, 0xc53ebb25, 0x42657a90, 0x74e3614c, 0x365c4048, 0x7cf9f3a2, 0x7f2addb0,
- 0xe6bf09b0, 0x1165fa5b, 0xcef84e43, 0x895be7cf, 0xb2116c4a, 0xa423108a, 0xa3bec236, 0x196db14c,
- 0xe05f6f4f, 0x07ee0118, 0xdcb8f8ce, 0xbd5e7918, 0x2159ab4d, 0x8ae54170, 0x527b0905, 0x7c8d3d44,
- 0x0d552705, 0xe5b21cad, 0x1b8ae64e, 0xc79cab55, 0x4e88e2bc, 0x444c1581, 0x86147c4c, 0xb4222648,
- 0x4136daad, 0x437ea22e, 0x2b92694c, 0x154baa6b, 0x0555795b, 0x9b484232, 0x6944f181, 0x036a6259,
- 0x1808ff60, 0xb0403148, 0x7b5e1b59, 0xdd30fb62, 0x4583266c, 0xb289c96d, 0x35e4aa6b, 0x50a23532,
- 0x3f1263c0, 0x763aae6c, 0xa729c144, 0x5ee5c64c, 0x02bf35d0, 0x367f3ac6, 0xfe547940, 0x2e1ea353,
- 0xe798ee48, 0x6c058495, 0x755dd5cb, 0x2ca6ef63, 0x7a0574bc, 0x9ac81c2e, 0xa5b33e44, 0x4fe69953,
- 0xf9556d62, 0x086a1bc6, 0xac28126c, 0x4fa7e6ad, 0xd4293d3e, 0x4e4f764b, 0x718849ad, 0x8139ff18,
- 0x4c6118b9, 0x65444c90, 0x371eeda9, 0xe2b4c0ad, 0xcd01f5da, 0x7671c344, 0x3021f518, 0x26369c4b,
- 0xd7f6f360, 0xdb55336c, 0xccdc7d18, 0x51d732c6, 0x335b5b4c, 0x094c2d05, 0x0dd546a6, 0x83d33118,
- 0x33dcff6d, 0xfd40b64c, 0x86e93f18, 0x87e2c780, 0xf0e1c1b2, 0xc67be347, 0x1df9d243, 0x6a646dae,
- 0xb0833b47, 0x8f457e4c, 0x0dbbe2bc, 0x4ac048c6, 0x7cc2194c, 0x1c84bb25, 0xb66b8218, 0xe3ee027b,
- 0x5cd4048e, 0xadcb0b18, 0xdc036e18, 0xb62e7999, 0xdee95243, 0x1ccdc344, 0x91cde560, 0xc8e0f460,
- 0xbea0f1c0, 0x35747b6d, 0x9686bb25, 0x28ce3c47, 0xaf0e5e48, 0x87f58f4b, 0x124dd9a2, 0xa21463c0,
- 0xa8f94952, 0xf71fd586, 0xe6fa056c, 0x92b86bb8, 0x707d6981, 0x22870732, 0x116fef62, 0xe0fd3ead,
- 0x78c2814e, 0x95d882c3, 0xdb3cba32, 0xe8b0e2bc, 0xb9c69b18, 0xe29ed783, 0x26c01118, 0xcbcd8451,
- 0xf1d02e18, 0x1b55aead, 0xb5549bc0, 0x47baa232, 0xbcf8f1c0, 0xae29dbb2, 0x0b881cd2, 0x75c8bb25,
+ 0x14851955, 0xc7113b25, 0xa6db048e, 0x77606505, 0x4f163b25, 0x567c692e, 0x25e02a64, 0x10143b25,
+ 0x93123b25, 0xa463f8a2, 0xef218abc, 0x25133b25, 0xe189bb25, 0xc0f83eb2, 0x6ab7c936, 0xa3624c90,
+ 0x6af8c4d9, 0x38c55b80, 0xb21f09b0, 0x33e7a5bc, 0xf558fb94, 0x6a5c4c90, 0x20d0048e, 0x14d1048e,
+ 0xcabd2e4e, 0x26bfd35f, 0x065e8abc, 0xccce1c2e, 0x2a55ec6d, 0xcd01f5da, 0x0bef32c6, 0x991d5fc0,
+ 0x6f4d4550, 0x0f35831f, 0xc7183b25, 0x8c7b0905, 0x7a9cbb25, 0x7eafa951, 0x86579bc0, 0xa15a4450,
+ 0xe5425177, 0x876e8ad5, 0xf6946257, 0x40c5ffad, 0x2e209d53, 0x6262e773, 0x42ef4c90, 0x9fc351c5,
+ 0x45ac795b, 0x6ac66d4f, 0x0a588abc, 0x9d411787, 0x8f9bbb25, 0xc4288368, 0xf745535b, 0x9c7086cf,
+ 0xc4422e4e, 0xc2533532, 0x84945250, 0x8b5d715e, 0x0f331c73, 0x228a9bd8, 0x4f3f0849, 0x17f4bbd5,
+ 0xc0e64a4a, 0xc53ebb25, 0x8dfab7ad, 0x36097e40, 0x2a27966b, 0x307d8abc, 0x1a32c405, 0xcf8d3c41,
+ 0x809f8705, 0x21f232c6, 0x64693660, 0x83b763c0, 0xc613ec68, 0xaf517462, 0x8f61e497, 0xae7b0451,
+ 0xafd61955, 0x2b85d772, 0xde0cf062, 0xee4ec780, 0xef6aa56f, 0x09b85d61, 0xac44f6cc, 0xc0b73505,
+ 0x0dedb944, 0x554d6f4c, 0x627dfe42, 0x48ca34ae, 0x272371d4, 0xf252a5bc, 0x8740f718, 0x262371d4,
+ 0x3ce82760, 0xe17c8845, 0x7c17332a, 0x4f5abb25, 0x07eccf57, 0x183f6018, 0xcb4b5f5c, 0xc34a0d47,
+ 0x60a4c780, 0xe9c2784c, 0xbccac24d, 0xc143f03c, 0x0260ba7c, 0x4a81ae58, 0xe131b843, 0x1dae7fd5,
+ 0x75d041ad, 0x390c7ed0, 0xaeac6d62, 0x8de20e4c, 0x915ee097, 0x1a3e1049, 0x8aca6f18, 0xd4470444,
+ 0x4856b3ad, 0x387e211b, 0xd191feb6, 0xe3bd0d41, 0x130009b0, 0xdf18be43, 0xdf143b25, 0x1e93e66d,
+ 0x41cfa262, 0x859baa51, 0x3618aa6b, 0x74c5f1c0, 0x3c14226c, 0x5c3cd070, 0xbc671b4f, 0x3f5871d5,
+ 0x37011e02, 0xfe53186c, 0xd39bd176, 0x3822b718, 0xe27d3060, 0xabee32c6, 0xc697c818, 0xd22cde50,
+ 0xc4cc6c3a, 0xd24ccd43, 0xd450bb25, 0x4101ee43, 0x20f232c6, 0xb7997845, 0xd4e3c162, 0x2fbe7670,
+ 0x41a5ee52, 0x800a201b, 0x4699ccda, 0xfcabb552, 0xde53ad32, 0x61668c18, 0xca9ec24e, 0x8b1eac49,
+ 0xb990b142, 0xf1e1784d, 0x30d04147, 0x785a995b, 0x12d14acc, 0x39d43680, 0x65e70844, 0x54783b18,
+ 0x232a3a63, 0x4e0a194f, 0x2b813b18, 0x2ac0bc49, 0x6af1ae51, 0x3256d062, 0x13d72bd9, 0xa5496444,
+ 0xbc944c47, 0x7d35bdd5, 0x109f2446, 0x16ef2e25, 0xe2f2784b, 0xee5ddaac, 0xc7889718, 0xaf49be6d,
+ 0xc914a443, 0x1d2bc24e, 0x82199d5d, 0x689c226c, 0x04441b46, 0x1feca832, 0x94208c55, 0x6756a149,
+ 0x09dee8d8, 0x1435e9a9, 0x82859f32, 0xadf0a662, 0x2f2bb856, 0x756bcd5a, 0x6b6be917, 0x1c40604a,
+ 0xeec4b749, 0x4d44a6b8, 0x162d1cb0, 0x22f232c6, 0x5f2012ad, 0x35612053, 0x02b35e47, 0x2d5c3f44,
+ 0x6904ef17, 0xef8a0b4c, 0xe6908932, 0x0df86c76, 0x3669343c, 0xdd8ba87c, 0x35841386, 0xb406e044,
+ 0x14a6946d, 0x6a448e3f, 0x2341295e, 0xb2837325, 0x82cf0c05, 0xa64d4141, 0xeb24c672, 0x4282ffda,
+ 0xccf2336c, 0x64813fbc, 0x9c81d259, 0xfbe6ed60, 0xc24a1c6c, 0x470ddc48, 0xd4dcaf42, 0x4c373fb2,
+ 0xbb9589d9, 0x7e431bc6, 0x3d24be43, 0xf417af44, 0x83f05243, 0xbe022363, 0x10b71d5d, 0xaf4b88d5,
+ 0xc3b66644, 0x31d30b71, 0xa056aa6b, 0x48db0364, 0x9780f5ac, 0x763aa0ad, 0x8ebcfe40, 0x241847ad,
+ 0xacdbf562, 0xfd09f743, 0x4f211c60, 0x0d963468, 0x80db149a, 0x18e8b944, 0xbcc27746, 0x8f6ce95f,
+ 0xde2cee2e, 0x45a71457, 0xde894ead, 0x024cd348, 0x2e0e74ce, 0x23300cac, 0x90527f62, 0x1d66e56d,
+ 0x83eddb8d, 0x0850f555, 0xe9a4e797, 0x0ef1ab56, 0x140ed98e, 0x2d3f944d, 0x0b6d18bc, 0xab33ca49,
+ 0xaed3b962, 0xc8a0f155, 0xb3eb9c32, 0xfc06424b, 0x927af8ac, 0xdf0119bc, 0xf7ba2452, 0x26590c05,
+ 0x0ec0cb6d, 0x337b252d, 0xe7b04a97, 0x5cc4a505, 0x9e81884a, 0xd052534b, 0xf7aa7761, 0x6666b527,
+ 0x49a4fd62, 0x3f715247, 0x902baa46, 0x7645812e, 0xbf771240, 0xe58e2451, 0xbb95fca2, 0x35204718,
+ 0x759138ae, 0x84300edf, 0x67140d47, 0x2c34465f, 0x260d0f18, 0xfd985c32, 0x3ba94cb2, 0x8067b545,
+ 0x062ac825, 0xdee9de59, 0x6254bf32, 0x9b6d2b44, 0xbebd7670, 0x3c55b46c, 0x5e8e5561, 0xa6d9a656,
+ 0x631fe149, 0x102f0378, 0xf4ede844, 0x34b94b3e, 0x73cdd55a, 0xd114c850, 0x7b6c5343, 0x6a3dde47,
+ 0x385da2b8, 0xf5f8c3d2, 0xe44c0654, 0xa4cb42bb, 0xf53fd176, 0xa424a14b, 0x79b38856, 0xdb717b5d,
+ 0x97f0b8bf, 0x031c4627, 0x9731d35a, 0x7bd81e4c, 0x43a850bc, 0xa336ff71, 0xbabd0b59, 0x9767bc73,
+ 0x1c131d4c, 0x06a47744, 0x1f5dbe5e, 0xf76f18bc, 0x560ab918, 0xd7cb0202, 0x569b326c, 0x52024c72,
+ 0x47525a5f, 0xd36d475f, 0x2e7d5dcc, 0x60330202, 0xd13c026c, 0x1660d7b0, 0x1a042f4e, 0xe644005e,
+ 0x5c53ba41, 0xc5adf651, 0x84e15d62, 0xcb76364d, 0x78ec8573, 0x5f6a06ae, 0xac8d3347, 0xd8758fd5,
+ 0x91c5351f, 0xdd6d67b1, 0x6027e53c, 0x308bba6d, 0x15448945, 0x612d454b, 0x3a10a143, 0x9b38cf56,
+ 0x3c44c556, 0xffb8784c, 0x5409b04b, 0xab2f7661, 0xa286534b, 0x0476c944, 0xd9cf4a52, 0x9cfa276c,
+ 0xaf07936b, 0xfcd02e32, 0x2361db8d, 0xc62c878d, 0x560ae740, 0xb21d0818, 0x7a2c4605, 0x8cc6a73b,
+ 0x5757be56, 0x50f1e218, 0x13b9194f, 0x48eb17ad, 0x4279112e, 0xf92a3fbc, 0x8ecc0202, 0xe93237ae,
+ 0x9bcfc80e, 0x4d72a343, 0xb97eed8d, 0x6732b55e, 0x14fdab43, 0x05e502d4, 0x88bd436d, 0xf4985a86,
+ 0xa12f8156, 0x2a91052e, 0xa651d98e, 0x2f750947, 0x61fd5455, 0x8bbcb66e, 0xd7383a60, 0xd9d3945c,
+ 0x52e5ac2e, 0x5f7a49be, 0x59036a44, 0x4b7b1978, 0x3a88ca4e, 0x910953b2, 0xc744996d, 0x0b6277c7,
+ 0x02a1a6b8, 0x0234d9ad, 0x0e7b8f45, 0x48738653, 0x3a1a5447, 0x0fdc4950, 0x672d5847, 0x04e44448,
+ 0x7750945c, 0x602f3260, 0xf5b42201, 0x5c05922e, 0x203c5332, 0x1f7c484b, 0x1b2d8caf, 0xbc99e797,
+ 0xe695ed62, 0x11b38375, 0x55b84bb2, 0xfce349be, 0x7181456a, 0x4f51f643, 0x66bb7e52, 0x5d235db2,
+ 0xb8c52ab2, 0x111b90d9, 0xa80eb118
};
class CMainParams : public CChainParams {
@@ -143,9 +124,9 @@ public:
assert(genesis.hashMerkleRoot == uint256("0x5b2a3f53f605d62c53e62932dac6925e3d74afa5a4b459745c36d42d0ed26a69"));
vSeeds.push_back(CDNSSeedData("dogecoin.com", "seed.dogecoin.com"));
- vSeeds.push_back(CDNSSeedData("mophides.com", "seed.mophides.com"));
- vSeeds.push_back(CDNSSeedData("dglibrary.org", "seed.dglibrary.org"));
- vSeeds.push_back(CDNSSeedData("dogechain.info", "seed.dogechain.info"));
+ vSeeds.push_back(CDNSSeedData("multidoge.org", "seed.multidoge.org"));
+ vSeeds.push_back(CDNSSeedData("multidoge.org", "seed2.multidoge.org"));
+ vSeeds.push_back(CDNSSeedData("doger.dogecoin.com", "seed.doger.dogecoin.com"));
// Workaround for Boost not being quite compatible with C++11;
std::vector<unsigned char> pka = list_of(30);
diff --git a/src/clientversion.h b/src/clientversion.h
index 08c74fd09..ffd602f65 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -11,7 +11,7 @@
// These need to be macros, as version.cpp's and dogecoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 8
-#define CLIENT_VERSION_REVISION 2
+#define CLIENT_VERSION_REVISION 3
#define CLIENT_VERSION_BUILD 0
// Set to true for release, false for prerelease or test build
diff --git a/src/compat.h b/src/compat.h
index 8fbafb6cc..1b3a60d11 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -59,19 +59,4 @@ typedef u_int SOCKET;
#define SOCKET_ERROR -1
#endif
-inline int myclosesocket(SOCKET& hSocket)
-{
- if (hSocket == INVALID_SOCKET)
- return WSAENOTSOCK;
-#ifdef WIN32
- int ret = closesocket(hSocket);
-#else
- int ret = close(hSocket);
-#endif
- hSocket = INVALID_SOCKET;
- return ret;
-}
-#define closesocket(s) myclosesocket(s)
-
-
#endif
diff --git a/src/init.cpp b/src/init.cpp
index 1737bb069..90a9e681e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -62,7 +62,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),
};
@@ -183,7 +184,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;
@@ -236,9 +237,8 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 22556 or testnet: 44556)") + "\n";
- strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS proxy") + "\n";
+ strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- strUsage += " -socks=<n> " + _("Select SOCKS version for -proxy (4 or 5, default: 5)") + "\n";
strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
#ifdef USE_UPNP
#if USE_UPNP
@@ -247,6 +247,8 @@ std::string HelpMessage(HelpMessageMode hmm)
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";
@@ -479,11 +481,11 @@ bool AppInit2(boost::thread_group& threadGroup)
nLocalServices |= NODE_BLOOM;
}
- 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) {
@@ -527,7 +529,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);
@@ -549,6 +551,12 @@ bool AppInit2(boost::thread_group& threadGroup)
// Check for -debugnet (deprecated)
if (GetBoolArg("-debugnet", false))
InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net"));
+ // Check for -socks - as this is a privacy risk to continue, exit here
+ if (mapArgs.count("-socks"))
+ return InitError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));
+ // Check for -tor - as this is a privacy risk to continue, exit here
+ if (GetBoolArg("-tor", false))
+ return InitError(_("Error: Unsupported argument -tor found, use -onion."));
fBenchmark = GetBoolArg("-benchmark", false);
mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest()));
@@ -732,10 +740,6 @@ bool AppInit2(boost::thread_group& threadGroup)
RegisterNodeSignals(GetNodeSignals());
- int nSocksVersion = GetArg("-socks", 5);
- if (nSocksVersion != 4 && nSocksVersion != 5)
- return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
-
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
@@ -751,6 +755,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")) {
@@ -759,12 +772,10 @@ bool AppInit2(boost::thread_group& threadGroup)
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));
if (!IsLimited(NET_IPV4))
- SetProxy(NET_IPV4, addrProxy, nSocksVersion);
- if (nSocksVersion > 4) {
- if (!IsLimited(NET_IPV6))
- SetProxy(NET_IPV6, addrProxy, nSocksVersion);
- SetNameProxy(addrProxy, nSocksVersion);
- }
+ SetProxy(NET_IPV4, addrProxy);
+ if (!IsLimited(NET_IPV6))
+ SetProxy(NET_IPV6, addrProxy);
+ SetNameProxy(addrProxy);
fProxy = true;
}
@@ -782,24 +793,32 @@ bool AppInit2(boost::thread_group& threadGroup)
addrOnion = mapArgs.count("-onion")?CService(mapArgs["-onion"], 9050):CService(mapArgs["-tor"], 9050);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs.count("-onion")?mapArgs["-onion"]:mapArgs["-tor"]));
- SetProxy(NET_TOR, addrOnion, 5);
+ SetProxy(NET_TOR, addrOnion);
SetReachable(NET_TOR);
}
// see Step 2: parameter interactions for more information about these
- fNoListen = !GetBoolArg("-listen", true);
+ fListen = GetBoolArg("-listen", true);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", true);
bool fBound = false;
- if (!fNoListen) {
- if (mapArgs.count("-bind")) {
+ if (fListen) {
+ 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;
diff --git a/src/main.cpp b/src/main.cpp
index ed237a73c..9d1eca948 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -207,9 +207,13 @@ struct CBlockReject {
// processing of incoming data is done after the ProcessMessage call returns,
// and we're no longer holding the node's locks.
struct CNodeState {
+ //! The peer's address
+ CService address;
+ //! Whether we have a fully established connection.
+ bool fCurrentlyConnected;
// 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;
@@ -223,6 +227,7 @@ struct CNodeState {
int64_t nLastBlockProcess;
CNodeState() {
+ fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
nBlocksToDownload = 0;
@@ -253,12 +258,16 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName;
+ state.address = pnode->addr;
}
void FinalizeNode(NodeId nodeid) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
+ if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
+ AddressCurrentlyConnected(state->address);
+ }
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight)
mapBlocksInFlight.erase(entry.hash);
BOOST_FOREACH(const uint256& hash, state->vBlocksToDownload)
@@ -1571,7 +1580,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;
@@ -3737,7 +3747,7 @@ void static ProcessGetData(CNode* pfrom)
}
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
+bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
LogPrint("net", "received: %s (%" PRIszu" bytes)\n", strCommand, vRecv.size());
@@ -3822,7 +3832,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!pfrom->fInbound)
{
// Advertise our address
- if (!fNoListen && !IsInitialBlockDownload())
+ if (fListen && !IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
@@ -3870,6 +3880,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "verack")
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
+
+ // Mark this node as currently connected, so we update its timestamp later.
+ if (pfrom->fNetworkNode) {
+ LOCK(cs_main);
+ State(pfrom->GetId())->fCurrentlyConnected = true;
+ }
}
@@ -4163,6 +4179,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
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, tx.GetHash());
}
int nDoS = 0;
if (state.IsInvalid(nDoS))
@@ -4257,7 +4278,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "pong")
{
- int64_t pingUsecEnd = GetTimeMicros();
+ int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
bool bPingFinished = false;
@@ -4426,11 +4447,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
- // Update the last seen time for this node's address
- if (pfrom->fNetworkNode)
- if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
- AddressCurrentlyConnected(pfrom->addr);
-
return true;
}
@@ -4513,7 +4529,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv);
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime);
boost::this_thread::interruption_point();
}
catch (std::ios_base::failure& e)
@@ -4572,8 +4588,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// RPC ping request by user
pingSend = true;
}
- if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
- // Ping automatically sent as a keepalive
+ if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
+ // Ping automatically sent as a latency probe & keepalive.
pingSend = true;
}
if (pingSend) {
@@ -4581,15 +4597,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
while (nonce == 0) {
RAND_bytes((unsigned char*)&nonce, sizeof(nonce));
}
- pto->nPingNonceSent = nonce;
pto->fPingQueued = false;
+ pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
- // Take timestamp as close as possible before transmitting ping
- pto->nPingUsecStart = GetTimeMicros();
+ pto->nPingNonceSent = nonce;
pto->PushMessage("ping", nonce);
} else {
- // Peer is too old to support ping command with nonce, pong will never arrive, disable timing
- pto->nPingUsecStart = 0;
+ // Peer is too old to support ping command with nonce, pong will never arrive.
+ pto->nPingNonceSent = 0;
pto->PushMessage("ping");
}
}
@@ -4611,7 +4626,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pnode->setAddrKnown.clear();
// Rebroadcast our address
- if (!fNoListen)
+ if (fListen)
{
CAddress addr = GetLocalAddress(&pnode->addr);
if (addr.IsRoutable())
@@ -4650,11 +4665,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;
}
diff --git a/src/net.cpp b/src/net.cpp
index f337447ff..279ee4d76 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -36,9 +36,31 @@
#define MSG_NOSIGNAL 0
#endif
+// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
+// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
+#ifdef WIN32
+#ifndef PROTECTION_LEVEL_UNRESTRICTED
+#define PROTECTION_LEVEL_UNRESTRICTED 10
+#endif
+#ifndef IPV6_PROTECTION_LEVEL
+#define IPV6_PROTECTION_LEVEL 23
+#endif
+#endif
+
using namespace std;
using namespace boost;
+namespace {
+ const int MAX_OUTBOUND_CONNECTIONS = 8;
+
+ struct ListenSocket {
+ SOCKET socket;
+ bool whitelisted;
+
+ ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
+ };
+}
+
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
@@ -46,6 +68,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
// Global state variables
//
bool fDiscover = true;
+bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
CCriticalSection cs_mapLocalHost;
map<CNetAddr, LocalServiceInfo> mapLocalHost;
@@ -54,7 +77,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;
int nMaxOutboundConnections = 8;
@@ -98,7 +121,7 @@ unsigned short GetListenPort()
// find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{
- if (fNoListen)
+ if (!fListen)
return false;
int nBestScore = -1;
@@ -313,7 +336,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
{
if (!RecvLine(hSocket, strLine))
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
if (pszKeyword == NULL)
@@ -324,7 +347,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
break;
}
}
- closesocket(hSocket);
+ CloseSocket(hSocket);
if (strLine.find("<") != string::npos)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
@@ -338,7 +361,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
return true;
}
}
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("GetMyExternalIP() : connection closed");
}
@@ -499,8 +522,7 @@ void CNode::CloseSocketDisconnect()
if (hSocket != INVALID_SOCKET)
{
LogPrint("net", "disconnecting node %s\n", addrName);
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
+ CloseSocket(hSocket);
}
// in case this fails, we'll empty the recv buffer when the CNode is deleted
@@ -513,11 +535,6 @@ void CNode::CloseSocketDisconnect()
pnodeSync = NULL;
}
-void CNode::Cleanup()
-{
-}
-
-
void CNode::PushVersion()
{
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -570,6 +587,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)
@@ -586,6 +621,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,
@@ -630,8 +666,16 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
if (handled < 0)
return false;
+ if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
+ LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId());
+ return false;
+ }
+
pch += handled;
nBytes -= handled;
+
+ if (msg.complete())
+ msg.nTime = GetTimeMicros();
}
return true;
@@ -759,7 +803,6 @@ void ThreadSocketHandler()
// close socket and cleanup
pnode->CloseSocketDisconnect();
- pnode->Cleanup();
// hold in disconnected pool until all refs are released
if (pnode->fNetworkNode || pnode->fInbound)
@@ -803,7 +846,6 @@ void ThreadSocketHandler()
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
}
-
//
// Find which sockets have data to receive
//
@@ -820,11 +862,12 @@ 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;
}
+
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -885,58 +928,61 @@ void ThreadSocketHandler()
MilliSleep(timeout.tv_usec/1000);
}
-
//
// Accept new connections
//
- BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
- if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
+ BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
{
- struct sockaddr_storage sockaddr;
- socklen_t len = sizeof(sockaddr);
- SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
- CAddress addr;
- int nInbound = 0;
-
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
- LogPrintf("Warning: Unknown socket family\n");
-
+ if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
{
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
- }
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
+ CAddress addr;
+ int nInbound = 0;
- if (hSocket == INVALID_SOCKET)
- {
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK)
- LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
- }
- else if (nInbound >= nMaxConnections - nMaxOutboundConnections)
- {
- closesocket(hSocket);
- }
- else if (CNode::IsBanned(addr))
- {
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
- closesocket(hSocket);
- }
- else
- {
- LogPrint("net", "accepted connection %s\n", addr.ToString());
- CNode* pnode = new CNode(hSocket, addr, "", true);
- pnode->AddRef();
+ if (hSocket != INVALID_SOCKET)
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ LogPrintf("Warning: Unknown socket family\n");
+
+ bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->fInbound)
+ nInbound++;
+ }
+
+ if (hSocket == INVALID_SOCKET)
+ {
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK)
+ LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
+ }
+ else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
+ {
+ CloseSocket(hSocket);
+ }
+ else if (CNode::IsBanned(addr) && !whitelisted)
+ {
+ LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ CloseSocket(hSocket);
+ }
+ else
+ {
+ LogPrint("net", "accepted connection %s\n", addr.ToString());
+ CNode* pnode = new CNode(hSocket, addr, "", true);
+ pnode->AddRef();
+ pnode->fWhitelisted = whitelisted;
+
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
}
}
}
-
//
// Service each socket
//
@@ -1010,23 +1056,27 @@ void ThreadSocketHandler()
//
// Inactivity checking
//
- if (pnode->vSendMsg.empty())
- pnode->nLastSendEmpty = GetTime();
- if (GetTime() - pnode->nTimeConnected > 60)
+ int64_t nTime = GetTime();
+ if (nTime - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
LogPrint("net", "socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
+ else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
+ {
+ LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
+ pnode->fDisconnect = true;
+ }
+ else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
{
- LogPrintf("socket not sending\n");
+ LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastRecv > 90*60)
+ else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
{
- LogPrintf("socket inactivity timeout\n");
+ LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
pnode->fDisconnect = true;
}
}
@@ -1310,8 +1360,7 @@ void ThreadOpenConnections()
int nTries = 0;
while (true)
{
- // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
- CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
+ CAddress addr = addrman.Select();
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
@@ -1557,7 +1606,7 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, string& strError)
+bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@@ -1580,18 +1629,16 @@ bool BindListenPort(const CService &addrBind, string& strError)
return false;
}
+#ifndef WIN32
#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
-
-#ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
- // the program was closed and restarted. Not an issue on windows.
+ // the program was closed and restarted. Not an issue on windows!
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
-
#ifdef WIN32
// Set to non-blocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@@ -1615,10 +1662,8 @@ bool BindListenPort(const CService &addrBind, string& strError)
#endif
#endif
#ifdef WIN32
- int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
- int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
- // this call is allowed to fail
- setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+ int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#endif
}
@@ -1630,6 +1675,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
+ CloseSocket(hListenSocket);
return false;
}
LogPrintf("Bound to %s\n", addrBind.ToString());
@@ -1639,12 +1685,13 @@ bool BindListenPort(const CService &addrBind, string& strError)
{
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
+ CloseSocket(hListenSocket);
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;
@@ -1771,11 +1818,11 @@ public:
// Close sockets
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)
- LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
+ CloseSocket(pnode->hSocket);
+ BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
+ if (hListenSocket.socket != INVALID_SOCKET)
+ if (!CloseSocket(hListenSocket.socket))
+ LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
// clean up some globals (to help leak detection)
BOOST_FOREACH(CNode *pnode, vNodes)
@@ -1784,6 +1831,7 @@ public:
delete pnode;
vNodes.clear();
vNodesDisconnected.clear();
+ vhListenSocket.clear();
delete semOutbound;
semOutbound = NULL;
delete pnodeLocalHost;
diff --git a/src/net.h b/src/net.h
index 5862129fa..6fc1a8ba6 100644
--- a/src/net.h
+++ b/src/net.h
@@ -28,6 +28,7 @@
#include <boost/signals2/signal.hpp>
#include <openssl/rand.h>
+
class CAddrMan;
class CBlockIndex;
class CNode;
@@ -36,8 +37,14 @@ namespace boost {
class thread_group;
}
+/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
+static const int PING_INTERVAL = 2 * 60;
+/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
+static const int TIMEOUT_INTERVAL = 20 * 60;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
+/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
+static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
/** The maximum number of entries in mapAskFor */
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
@@ -53,7 +60,7 @@ CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
-bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
+bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
void StartNode(boost::thread_group& threadGroup);
bool StopNode();
void SocketSendData(CNode *pnode);
@@ -100,6 +107,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
extern bool fDiscover;
+extern bool fListen;
extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
@@ -143,6 +151,7 @@ public:
uint64_t nSendBytes;
uint64_t nRecvBytes;
bool fSyncNode;
+ bool fWhitelisted;
double dPingTime;
double dPingWait;
std::string addrLocal;
@@ -162,11 +171,14 @@ public:
CDataStream vRecv; // received message data
unsigned int nDataPos;
+ int64_t nTime; // time (in microseconds) of message receipt.
+
CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) {
hdrbuf.resize(24);
in_data = false;
nHdrPos = 0;
nDataPos = 0;
+ nTime = 0;
}
bool complete() const
@@ -212,7 +224,6 @@ public:
int64_t nLastSend;
int64_t nLastRecv;
- int64_t nLastSendEmpty;
int64_t nTimeConnected;
CAddress addr;
std::string addrName;
@@ -223,6 +234,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;
@@ -246,6 +258,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
@@ -268,10 +285,14 @@ public:
CCriticalSection cs_inventory;
std::multimap<int64_t, CInv> mapAskFor;
- // Ping time measurement
+ // Ping time measurement:
+ // The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
+ // Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
int64_t nPingUsecStart;
+ // Last measured round-trip time.
int64_t nPingUsecTime;
+ // Whether a ping is requested.
bool fPingQueued;
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
@@ -283,12 +304,12 @@ public:
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
- nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
+ fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
fInbound = fInboundIn;
@@ -328,8 +349,7 @@ public:
{
if (hSocket != INVALID_SOCKET)
{
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
+ CloseSocket(hSocket);
}
if (pfilter)
delete pfilter;
@@ -682,8 +702,6 @@ public:
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
- void Cleanup();
-
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
@@ -704,6 +722,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);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index e24a0a195..75b168322 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -25,7 +25,7 @@ using namespace std;
// Settings
static proxyType proxyInfo[NET_MAX];
-static proxyType nameproxyInfo;
+static CService nameProxy;
static CCriticalSection cs_proxyInfos;
int nConnectTimeout = 5000;
bool fNameLookup = false;
@@ -161,56 +161,12 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
return Lookup(pszName, addr, portDefault, false);
}
-bool static Socks4(const CService &addrDest, SOCKET& hSocket)
-{
- LogPrintf("SOCKS4 connecting %s\n", addrDest.ToString());
- if (!addrDest.IsIPv4())
- {
- closesocket(hSocket);
- return error("Proxy destination is not IPv4");
- }
- char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
- struct sockaddr_in addr;
- socklen_t len = sizeof(addr);
- if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
- {
- closesocket(hSocket);
- return error("Cannot get proxy destination address");
- }
- memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
- memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
- char* pszSocks4 = pszSocks4IP;
- int nSize = sizeof(pszSocks4IP);
-
- int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
- if (ret != nSize)
- {
- closesocket(hSocket);
- return error("Error sending to proxy");
- }
- char pchRet[8];
- if (recv(hSocket, pchRet, 8, 0) != 8)
- {
- closesocket(hSocket);
- return error("Error reading proxy response");
- }
- if (pchRet[1] != 0x5a)
- {
- closesocket(hSocket);
- if (pchRet[1] != 0x5b)
- LogPrintf("ERROR: Proxy returned error %d\n", pchRet[1]);
- return false;
- }
- LogPrintf("SOCKS4 connected %s\n", addrDest.ToString());
- return true;
-}
-
bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
LogPrintf("SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Hostname too long");
}
char pszSocks5Init[] = "\5\1\0";
@@ -219,18 +175,18 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet1[2];
if (recv(hSocket, pchRet1, 2, 0) != 2)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Proxy failed to initialize");
}
string strSocks5("\5\1");
@@ -242,23 +198,23 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)strSocks5.size())
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet2[4];
if (recv(hSocket, pchRet2, 4, 0) != 4)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet2[0] != 0x05)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
if (pchRet2[1] != 0x00)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
switch (pchRet2[1])
{
case 0x01: return error("Proxy error: general failure");
@@ -274,7 +230,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
}
if (pchRet2[2] != 0x00)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
char pchRet3[256];
@@ -286,23 +242,23 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
ret = recv(hSocket, pchRet3, 1, 0) != 1;
if (ret) {
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv;
break;
}
- default: closesocket(hSocket); return error("Error: malformed proxy response");
+ default: CloseSocket(hSocket); return error("Error: malformed proxy response");
}
if (ret)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error reading from proxy");
}
if (recv(hSocket, pchRet3, 2, 0) != 2)
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("Error reading from proxy");
}
LogPrintf("SOCKS5 connected %s\n", strDest);
@@ -336,7 +292,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
#endif
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
@@ -356,13 +312,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (nRet == 0)
{
LogPrint("net", "connection to %s timeout\n", addrConnect.ToString());
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
socklen_t nRetSize = sizeof(nRet);
@@ -373,13 +329,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
if (nRet != 0)
{
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
}
@@ -390,7 +346,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
}
@@ -406,7 +362,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR)
#endif
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
@@ -414,53 +370,49 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true;
}
-bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
+bool SetProxy(enum Network net, CService addrProxy) {
assert(net >= 0 && net < NET_MAX);
- if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5)
- return false;
- if (nSocksVersion != 0 && !addrProxy.IsValid())
+ if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
- proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
+ proxyInfo[net] = addrProxy;
return true;
}
bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
assert(net >= 0 && net < NET_MAX);
LOCK(cs_proxyInfos);
- if (!proxyInfo[net].second)
+ if (!proxyInfo[net].IsValid())
return false;
proxyInfoOut = proxyInfo[net];
return true;
}
-bool SetNameProxy(CService addrProxy, int nSocksVersion) {
- if (nSocksVersion != 0 && nSocksVersion != 5)
- return false;
- if (nSocksVersion != 0 && !addrProxy.IsValid())
+bool SetNameProxy(CService addrProxy) {
+ if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
- nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
+ nameProxy = addrProxy;
return true;
}
-bool GetNameProxy(proxyType &nameproxyInfoOut) {
+bool GetNameProxy(CService &nameProxyOut) {
LOCK(cs_proxyInfos);
- if (!nameproxyInfo.second)
+ if(!nameProxy.IsValid())
return false;
- nameproxyInfoOut = nameproxyInfo;
+ nameProxyOut = nameProxy;
return true;
}
bool HaveNameProxy() {
LOCK(cs_proxyInfos);
- return nameproxyInfo.second != 0;
+ return nameProxy.IsValid();
}
bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) {
- if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
+ if (addr == (CNetAddr)proxyInfo[i])
return true;
}
return false;
@@ -469,31 +421,18 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{
proxyType proxy;
-
- // no proxy needed
+ // no proxy needed (none set for target network)
if (!GetProxy(addrDest.GetNetwork(), proxy))
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout))
+ if (!ConnectSocketDirectly(proxy, hSocket, nTimeout))
return false;
-
// do socks negotiation
- switch (proxy.second) {
- case 4:
- if (!Socks4(addrDest, hSocket))
- return false;
- break;
- case 5:
- if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
- return false;
- break;
- default:
- closesocket(hSocket);
+ if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
- }
hSocketRet = hSocket;
return true;
@@ -507,30 +446,25 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SOCKET hSocket = INVALID_SOCKET;
- proxyType nameproxy;
- GetNameProxy(nameproxy);
+ CService nameProxy;
+ GetNameProxy(nameProxy);
- CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxy.second), port);
+ CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port);
if (addrResolved.IsValid()) {
addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout);
}
+
addr = CService("0.0.0.0:0");
- if (!nameproxy.second)
+
+ if (!HaveNameProxy())
return false;
- if (!ConnectSocketDirectly(nameproxy.first, hSocket, nTimeout))
+ // first connect to name proxy server
+ if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout))
+ return false;
+ // do socks negotiation
+ if (!Socks5(strDest, (unsigned short)port, hSocket))
return false;
-
- switch(nameproxy.second) {
- default:
- case 4:
- closesocket(hSocket);
- return false;
- case 5:
- if (!Socks5(strDest, port, hSocket))
- return false;
- break;
- }
hSocketRet = hSocket;
return true;
@@ -1270,3 +1204,16 @@ std::string NetworkErrorString(int err)
return strprintf("%s (%d)", s, err);
}
#endif
+
+bool CloseSocket(SOCKET& hSocket)
+{
+ if (hSocket == INVALID_SOCKET)
+ return false;
+#ifdef WIN32
+ int ret = closesocket(hSocket);
+#else
+ int ret = close(hSocket);
+#endif
+ hSocket = INVALID_SOCKET;
+ return ret != SOCKET_ERROR;
+}
diff --git a/src/netbase.h b/src/netbase.h
index 5fd8be4ac..f816c6437 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -163,14 +163,14 @@ class CService : public CNetAddr
)
};
-typedef std::pair<CService, int> proxyType;
+typedef CService proxyType;
enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
-bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
+bool SetProxy(enum Network net, CService addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
-bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
+bool SetNameProxy(CService addrProxy);
bool HaveNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
@@ -181,5 +181,7 @@ bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nCon
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
+/** Close socket and set hSocket to INVALID_SOCKET */
+bool CloseSocket(SOCKET& hSocket);
#endif
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 8c961c825..c7341d315 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -319,26 +319,6 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="socksVersionLabel">
- <property name="text">
- <string>SOCKS &amp;Version:</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="buddy">
- <cstring>socksVersion</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QValueComboBox" name="socksVersion">
- <property name="toolTip">
- <string>SOCKS version of the proxy (e.g. 5)</string>
- </property>
- </widget>
- </item>
- <item>
<spacer name="horizontalSpacer_1_Network">
<property name="orientation">
<enum>Qt::Horizontal</enum>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index e8365fc25..eccb0b803 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -49,15 +49,8 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
ui->proxyPort->setEnabled(false);
ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
- /** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
- ui->socksVersion->setEnabled(false);
- ui->socksVersion->addItem("5", 5);
- ui->socksVersion->addItem("4", 4);
- ui->socksVersion->setCurrentIndex(0);
-
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
- connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
ui->proxyIp->installEventFilter(this);
@@ -175,7 +168,6 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
- mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);
/* Window */
#ifndef Q_OS_MAC
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 15ecca503..2c0bd23be 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -123,11 +123,6 @@ void OptionsModel::Init()
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
- if (!settings.contains("nSocksVersion"))
- settings.setValue("nSocksVersion", 5);
- // Only try to set -socks, if user has enabled fUseProxy
- if (settings.value("fUseProxy").toBool() && !SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()))
- addOverriddenOption("-socks");
// Display
if (!settings.contains("language"))
@@ -189,8 +184,6 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
return strlIpPort.at(1);
}
- case ProxySocksVersion:
- return settings.value("nSocksVersion", 5);
#ifdef ENABLE_WALLET
case Fee:
@@ -282,13 +275,6 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
break;
- case ProxySocksVersion: {
- if (settings.value("nSocksVersion") != value) {
- settings.setValue("nSocksVersion", value.toInt());
- setRestartRequired(true);
- }
- }
- break;
#ifdef ENABLE_WALLET
case Fee: // core option - can be changed on-the-fly
// Todo: Add is valid check and warn via message, if not
@@ -357,20 +343,16 @@ bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
// GUI settings can be overridden with -proxy.
proxyType curProxy;
if (GetProxy(NET_IPV4, curProxy)) {
- if (curProxy.second == 5) {
- proxy.setType(QNetworkProxy::Socks5Proxy);
- proxy.setHostName(QString::fromStdString(curProxy.first.ToStringIP()));
- proxy.setPort(curProxy.first.GetPort());
+ proxy.setType(QNetworkProxy::Socks5Proxy);
+ proxy.setHostName(QString::fromStdString(curProxy.ToStringIP()));
+ proxy.setPort(curProxy.GetPort());
- return true;
- }
- else
- return false;
+ return true;
}
else
proxy.setType(QNetworkProxy::NoProxy);
- return true;
+ return false;
}
void OptionsModel::setRestartRequired(bool fRequired)
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 31b7282b0..7fb35e6ee 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -345,20 +345,14 @@ void PaymentServer::initNetManager()
QNetworkProxy proxy;
- // Query active proxy (fails if no SOCKS5 proxy)
+ // Query active SOCKS5 proxy
if (optionsModel->getProxySettings(proxy)) {
- if (proxy.type() == QNetworkProxy::Socks5Proxy) {
- netManager->setProxy(proxy);
+ netManager->setProxy(proxy);
- qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
- }
- else
- qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
+ qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
}
else
- emit message(tr("Net manager warning"),
- tr("Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy."),
- CClientUIInterface::MSG_WARNING);
+ qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
connect(netManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(netRequestFinished(QNetworkReply*)));
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 267516c82..508c17cd0 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -71,7 +71,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", TestNet()));
#ifdef ENABLE_WALLET
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index f5d8fad49..86f960222 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -134,8 +134,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
}
- if (stats.fSyncNode)
- obj.push_back(Pair("syncnode", true));
+ obj.push_back(Pair("syncnode", stats.fSyncNode));
+ obj.push_back(Pair("whitelisted", stats.fWhitelisted));
ret.push_back(obj);
}
@@ -368,7 +368,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee)));
Array localAddresses;
{
diff --git a/src/serialize.h b/src/serialize.h
index a157048d5..738af4015 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -831,6 +831,35 @@ struct ser_streamplaceholder
typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
+class CSizeComputer
+{
+protected:
+ size_t nSize;
+
+public:
+ int nType;
+ int nVersion;
+
+ CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
+
+ CSizeComputer& write(const char *psz, int nSize)
+ {
+ this->nSize += nSize;
+ return *this;
+ }
+
+ template<typename T>
+ CSizeComputer& operator<<(const T& obj)
+ {
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ size_t size() const {
+ return nSize;
+ }
+};
+
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.
diff --git a/src/util.cpp b/src/util.cpp
index d1f76f6a5..d0e6bfee7 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -97,7 +97,6 @@ bool fDaemon = false;
bool fServer = false;
string strMiscWarning;
bool fBloomFilters = true;
-bool fNoListen = false;
bool fLogTimestamps = false;
volatile bool fReopenDebugLog = false;
CClientUIInterface uiInterface;
diff --git a/src/util.h b/src/util.h
index 002946149..ffe346e5f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -115,7 +115,6 @@ extern bool fPrintToDebugLog;
extern bool fServer;
extern std::string strMiscWarning;
extern bool fBloomFilters;
-extern bool fNoListen;
extern bool fLogTimestamps;
extern volatile bool fReopenDebugLog;