diff options
| author | langerhans <[email protected]> | 2015-07-02 19:54:14 +0200 |
|---|---|---|
| committer | langerhans <[email protected]> | 2015-07-02 19:54:14 +0200 |
| commit | 66eb58e86c04432d0ef218e0df9d6b28e0ea5904 (patch) | |
| tree | f96a918113239134511c06153cd87b50f1c23776 | |
| parent | Merge branch '1.8.2-dev' into 1.8-maint (diff) | |
| parent | Merge pull request #1191 from langerhans/1.8.3-releaseprep (diff) | |
| download | discoin-66eb58e86c04432d0ef218e0df9d6b28e0ea5904.tar.xz discoin-66eb58e86c04432d0ef218e0df9d6b28e0ea5904.zip | |
Merge branch '1.8.3-dev' into 1.8-maint
| -rw-r--r-- | RELEASE_NOTES_1.8.3.md | 24 | ||||
| -rw-r--r-- | configure.ac | 4 | ||||
| -rw-r--r-- | doc/release-notes/RELEASE_NOTES_1.8.2.md (renamed from RELEASE_NOTES_1.8.2.md) | 0 | ||||
| -rwxr-xr-x | qa/pull-tester/run-bitcoind-for-test.sh.in | 2 | ||||
| -rw-r--r-- | src/addrman.cpp | 326 | ||||
| -rw-r--r-- | src/addrman.h | 446 | ||||
| -rw-r--r-- | src/chainparams.cpp | 137 | ||||
| -rw-r--r-- | src/clientversion.h | 2 | ||||
| -rw-r--r-- | src/compat.h | 15 | ||||
| -rw-r--r-- | src/init.cpp | 61 | ||||
| -rw-r--r-- | src/main.cpp | 62 | ||||
| -rw-r--r-- | src/net.cpp | 212 | ||||
| -rw-r--r-- | src/net.h | 37 | ||||
| -rw-r--r-- | src/netbase.cpp | 173 | ||||
| -rw-r--r-- | src/netbase.h | 8 | ||||
| -rw-r--r-- | src/qt/forms/optionsdialog.ui | 20 | ||||
| -rw-r--r-- | src/qt/optionsdialog.cpp | 8 | ||||
| -rw-r--r-- | src/qt/optionsmodel.cpp | 28 | ||||
| -rw-r--r-- | src/qt/paymentserver.cpp | 14 | ||||
| -rw-r--r-- | src/rpcmisc.cpp | 2 | ||||
| -rw-r--r-- | src/rpcnet.cpp | 6 | ||||
| -rw-r--r-- | src/serialize.h | 29 | ||||
| -rw-r--r-- | src/util.cpp | 1 | ||||
| -rw-r--r-- | src/util.h | 1 |
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; @@ -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 &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; |