diff --git a/src/base58.cpp b/src/base58.cpp index 69092bdd5b11..40e3b1cb336c 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -127,7 +127,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) std::string EncodeBase58(const std::vector& vch) { - return EncodeBase58(&vch[0], &vch[0] + vch.size()); + return EncodeBase58(vch.data(), vch.data() + vch.size()); } bool DecodeBase58(const std::string& str, std::vector& vchRet) @@ -177,7 +177,7 @@ void CBase58Data::SetData(const std::vector& vchVersionIn, const vchVersion = vchVersionIn; vchData.resize(nSize); if (!vchData.empty()) - memcpy(&vchData[0], pdata, nSize); + memcpy(vchData.data(), pdata, nSize); } void CBase58Data::SetData(const std::vector& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend) @@ -197,8 +197,8 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); vchData.resize(vchTemp.size() - nVersionBytes); if (!vchData.empty()) - memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); - memory_cleanse(&vchTemp[0], vchTemp.size()); + memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size()); + memory_cleanse(vchTemp.data(), vchTemp.size()); return true; } diff --git a/src/base58.h b/src/base58.h index b825533f6604..63fa97b8620b 100644 --- a/src/base58.h +++ b/src/base58.h @@ -118,8 +118,8 @@ class CBitcoinExtKeyBase : public CBase58Data { K ret; if (vchData.size() == Size) { - //if base58 encouded data not holds a ext key, return a !IsValid() key - ret.Decode(&vchData[0]); + // If base58 encoded data does not hold an ext key, return a !IsValid() key + ret.Decode(vchData.data()); } return ret; } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 95a414b64019..ded25027cafc 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -227,8 +227,8 @@ class CMainParams : public CChainParams nDefaultPort = 51472; // Note that of those with the service bits flag, most only support a subset of possible options - vSeeds.emplace_back("fuzzbawls.pw", "pivx.seed.fuzzbawls.pw", true); // Primary DNS Seeder from Fuzzbawls - vSeeds.emplace_back("fuzzbawls.pw", "pivx.seed2.fuzzbawls.pw", true); // Secondary DNS Seeder from Fuzzbawls + vSeeds.emplace_back("pivx.seed.fuzzbawls.pw", true); // Primary DNS Seeder from Fuzzbawls + vSeeds.emplace_back("pivx.seed2.fuzzbawls.pw", true); // Secondary DNS Seeder from Fuzzbawls base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 30); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 13); @@ -351,8 +351,8 @@ class CTestNetParams : public CChainParams nDefaultPort = 51474; // nodes with support for servicebits filtering should be at the top - vSeeds.emplace_back("fuzzbawls.pw", "pivx-testnet.seed.fuzzbawls.pw", true); - vSeeds.emplace_back("fuzzbawls.pw", "pivx-testnet.seed2.fuzzbawls.pw", true); + vSeeds.emplace_back("pivx-testnet.seed.fuzzbawls.pw", true); + vSeeds.emplace_back("pivx-testnet.seed2.fuzzbawls.pw", true); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 139); // Testnet pivx addresses start with 'x' or 'y' base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 19); // Testnet pivx script addresses start with '8' or '9' diff --git a/src/chainparams.h b/src/chainparams.h index 88c052f2edd9..adfc063a47da 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -19,9 +19,9 @@ #include struct CDNSSeedData { - std::string name, host; + std::string host; bool supportsServiceBitsFiltering; - CDNSSeedData(const std::string& strName, const std::string& strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {} + CDNSSeedData(const std::string& strHost, bool supportsServiceBitsFilteringIn = false) : host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {} }; struct SeedSpec6 { diff --git a/src/compressor.cpp b/src/compressor.cpp index 994d4932519f..a54f7ab6757f 100644 --- a/src/compressor.cpp +++ b/src/compressor.cpp @@ -89,7 +89,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector 0) { - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; - const int nblocks = vDataToHash.size() / 4; + const int nblocks = vDataToHash.size() / 4; - //---------- - // body - const uint8_t* blocks = &vDataToHash[0] + nblocks * 4; + //---------- + // body + const uint8_t* blocks = vDataToHash.data(); - for (int i = -nblocks; i; i++) { - uint32_t k1 = ReadLE32(blocks + i*4); + for (int i = 0; i < nblocks; ++i) { + uint32_t k1 = ReadLE32(blocks + i*4); - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; - h1 ^= k1; - h1 = ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } - //---------- - // tail - const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4); + //---------- + // tail + const uint8_t* tail = vDataToHash.data() + nblocks * 4; - uint32_t k1 = 0; + uint32_t k1 = 0; - switch (vDataToHash.size() & 3) { + switch (vDataToHash.size() & 3) { case 3: k1 ^= tail[2] << 16; case 2: @@ -56,7 +55,6 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector convertSeed6(const std::vector& vSeedsIn // one by discovery. CAddress GetLocalAddress(const CNetAddr* paddrPeer, ServiceFlags nLocalServices) { - CAddress ret(CService(CNetAddr(), GetListenPort()), NODE_NONE); + CAddress ret(CService(CNetAddr(), GetListenPort()), nLocalServices); CService addr; if (GetLocal(addr, paddrPeer)) { ret = CAddress(addr, nLocalServices); @@ -235,7 +235,7 @@ bool RemoveLocal(const CService& addr) /** Make a particular network entirely off-limits (no automatic connects to it) */ void SetLimited(enum Network net, bool fLimited) { - if (net == NET_UNROUTABLE) + if (net == NET_UNROUTABLE || net == NET_INTERNAL) return; LOCK(cs_mapLocalHost); vfLimited[net] = fLimited; @@ -453,34 +453,30 @@ void CConnman::ClearBanned() bool CConnman::IsBanned(CNetAddr ip) { - bool fResult = false; + LOCK(cs_setBanned); + for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++) { - LOCK(cs_setBanned); - for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++) - { - CSubNet subNet = (*it).first; - CBanEntry banEntry = (*it).second; + CSubNet subNet = (*it).first; + CBanEntry banEntry = (*it).second; - if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil) - fResult = true; + if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) { + return true; } } - return fResult; + return false; } bool CConnman::IsBanned(CSubNet subnet) { - bool fResult = false; - { - LOCK(cs_setBanned); - banmap_t::iterator i = setBanned.find(subnet); - if (i != setBanned.end()) { - CBanEntry banEntry = (*i).second; - if (GetTime() < banEntry.nBanUntil) - fResult = true; + LOCK(cs_setBanned); + banmap_t::iterator i = setBanned.find(subnet); + if (i != setBanned.end()) { + CBanEntry banEntry = (*i).second; + if (GetTime() < banEntry.nBanUntil) { + return true; } } - return fResult; + return false; } void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) @@ -1519,26 +1515,20 @@ void CConnman::ThreadDNSAddressSeed() std::vector vIPs; std::vector vAdd; ServiceFlags requiredServiceBits = nRelevantServices; - if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true)) { + std::string host = GetDNSHost(seed, &requiredServiceBits); + CNetAddr resolveSource; + if (!resolveSource.SetInternal(host)) { + continue; + } + if (LookupHost(host.c_str(), vIPs, 0, true)) { for (CNetAddr& ip : vIPs) { - int nOneDay = 24 * 3600; + int nOneDay = 24*3600; CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits); addr.nTime = GetTime() - 3 * nOneDay - GetRand(4 * nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); found++; } - } - if (interruptNet) { - return; - } - // TODO: The seed name resolve may fail, yielding an IP of [::], which results in - // addrman assigning the same source to results from different seeds. - // This should switch to a hard-coded stable dummy IP for each seed name, so that the - // resolve is not required at all. - if (!vIPs.empty()) { - CService seedSource; - Lookup(seed.name.c_str(), seedSource, 0, true); - addrman.Add(vAdd, seedSource); + addrman.Add(vAdd, resolveSource); } } } @@ -1632,7 +1622,7 @@ void CConnman::ThreadOpenConnections() if (!done) { LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); CNetAddr local; - LookupHost("127.0.0.1", local, false); + local.SetInternal("fixedseeds"); addrman.Add(convertSeed6(Params().FixedSeeds()), local); done = true; } @@ -2487,14 +2477,17 @@ CNode::~CNode() { CloseSocket(hSocket); - if (pfilter) - delete pfilter; + delete pfilter; } void CNode::AskFor(const CInv& inv) { - if (mapAskFor.size() > MAPASKFOR_MAX_SZ) + if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ) return; + // a peer may not have multiple non-responded queue positions for a single inv item + if (!setAskFor.insert(inv.hash).second) + return; + // We're using mapAskFor as a priority queue, // the key is the earliest time the request can be sent int64_t nRequestTime; @@ -2610,6 +2603,6 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) { std::vector vchNetGroup(ad.GetGroup()); - return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); + return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize(); } diff --git a/src/net.h b/src/net.h index 6f0eab8ac9b2..fa5f538fed70 100644 --- a/src/net.h +++ b/src/net.h @@ -69,6 +69,8 @@ static const bool DEFAULT_UPNP = false; #endif /** The maximum number of entries in mapAskFor */ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; +/** The maximum number of entries in setAskFor (larger due to getdata latency)*/ +static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** Disconnected peers are added to setOffsetDisconnectedPeers only if node has less than ENOUGH_CONNECTIONS */ @@ -222,7 +224,6 @@ class CConnman void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0); void AddNewAddresses(const std::vector& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); std::vector GetAddresses(); - void AddressCurrentlyConnected(const CService& addr); // Denial-of-service detection/prevention // The idea is to detect peers that are behaving @@ -624,6 +625,7 @@ class CNode std::vector vInventoryTierTwoToSend; RecursiveMutex cs_inventory; std::multimap mapAskFor; + std::set setAskFor; std::vector vBlockRequested; int64_t nNextInvSend; // Used for BIP35 mempool sending, also protected by cs_inventory @@ -791,9 +793,6 @@ class CNode vecRequestsFulfilled.push_back(strRequest); } - bool IsSubscribed(unsigned int nChannel); - void Subscribe(unsigned int nChannel, unsigned int nHops = 0); - void CancelSubscribe(unsigned int nChannel); void CloseSocketDisconnect(); bool DisconnectOldProtocol(int nVersionIn, int nVersionRequired, std::string strLastCommand = ""); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 96dde1668ea2..ccbd57ee58db 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1508,6 +1508,7 @@ bool static ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vR bool fMissingInputs = false; CValidationState state; + pfrom->setAskFor.erase(inv.hash); mapAlreadyAskedFor.erase(inv); if (ptx->ContainsZerocoins()) { @@ -2370,6 +2371,9 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); vGetData.clear(); } + } else { + //If we're not going to ask, don't expect a response. + pto->setAskFor.erase(inv.hash); } pto->mapAskFor.erase(pto->mapAskFor.begin()); } diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 87ce9e53a011..32d1e200dab4 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -16,10 +16,12 @@ static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; +// 0xFD + sha256("bitcoin")[0:5] +static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 }; + void CNetAddr::Init() { memset(ip, 0, sizeof(ip)); - scopeId = 0; } void CNetAddr::SetIP(const CNetAddr& ipIn) @@ -43,6 +45,18 @@ void CNetAddr::SetRaw(Network network, const uint8_t* ip_in) } } +bool CNetAddr::SetInternal(const std::string &name) +{ + if (name.empty()) { + return false; + } + unsigned char hash[32] = {}; + CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash); + memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix)); + memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix)); + return true; +} + bool CNetAddr::SetSpecial(const std::string& strName) { if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") { @@ -85,7 +99,7 @@ bool CNetAddr::IsIPv4() const bool CNetAddr::IsIPv6() const { - return (!IsIPv4() && !IsTor()); + return (!IsIPv4() && !IsTor() && !IsInternal()); } bool CNetAddr::IsRFC1918() const @@ -206,6 +220,9 @@ bool CNetAddr::IsValid() const if (IsRFC3849()) return false; + if (IsInternal()) + return false; + if (IsIPv4()) { // INADDR_NONE @@ -224,11 +241,19 @@ bool CNetAddr::IsValid() const bool CNetAddr::IsRoutable() const { - return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal()); + return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal()); +} + +bool CNetAddr::IsInternal() const +{ + return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0; } enum Network CNetAddr::GetNetwork() const { + if (IsInternal()) + return NET_INTERNAL; + if (!IsRoutable()) return NET_UNROUTABLE; @@ -245,6 +270,8 @@ std::string CNetAddr::ToStringIP() const { if (IsTor()) return EncodeBase32(&ip[6], 10) + ".onion"; + if (IsInternal()) + return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal"; CService serv(*this, 0); struct sockaddr_storage sockaddr; socklen_t socklen = sizeof(sockaddr); @@ -312,9 +339,15 @@ std::vector CNetAddr::GetGroup() const nClass = 255; nBits = 0; } - - // all unroutable addresses belong to the same group - if (!IsRoutable()) + // all internal-usage addresses get their own group + if (IsInternal()) + { + nClass = NET_INTERNAL; + nStartByte = sizeof(g_internal_prefix); + nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8; + } + // all other unroutable addresses belong to the same group + else if (!IsRoutable()) { nClass = NET_UNROUTABLE; nBits = 0; @@ -400,7 +433,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const REACH_PRIVATE }; - if (!IsRoutable()) + if (!IsRoutable() || IsInternal()) return REACH_UNREACHABLE; int ourNet = GetExtNetwork(this); @@ -546,7 +579,7 @@ std::vector CService::GetKey() const { std::vector vKey; vKey.resize(18); - memcpy(&vKey[0], ip, 16); + memcpy(vKey.data(), ip, 16); vKey[16] = port / 0x100; vKey[17] = port & 0x0FF; return vKey; @@ -559,7 +592,7 @@ std::string CService::ToStringPort() const std::string CService::ToStringIPPort() const { - if (IsIPv4() || IsTor()) { + if (IsIPv4() || IsTor() || IsInternal()) { return ToStringIP() + ":" + ToStringPort(); } else { return "[" + ToStringIP() + "]:" + ToStringPort(); diff --git a/src/netaddress.h b/src/netaddress.h index 7894e2aff5c2..ba4a9b72d2d4 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -22,6 +22,7 @@ enum Network { NET_IPV4, NET_IPV6, NET_TOR, + NET_INTERNAL, NET_MAX, }; @@ -31,7 +32,7 @@ class CNetAddr { protected: unsigned char ip[16]; // in network byte order - uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses + uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses public: CNetAddr(); @@ -45,6 +46,12 @@ class CNetAddr */ void SetRaw(Network network, const uint8_t* data); + /** + * Transform an arbitrary string into a non-routable ipv6 address. + * Useful for mapping resolved addresses back to their source. + */ + bool SetInternal(const std::string& name); + bool SetSpecial(const std::string& strName); // for Tor addresses bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) @@ -64,6 +71,7 @@ class CNetAddr bool IsTor() const; bool IsLocal() const; bool IsRoutable() const; + bool IsInternal() const; bool IsValid() const; bool IsMulticast() const; enum Network GetNetwork() const; diff --git a/src/netbase.cpp b/src/netbase.cpp index 442260e58a81..468a6d013d57 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -112,14 +112,20 @@ bool static LookupIntern(const char* pszName, std::vector& vIP, unsign struct addrinfo* aiTrav = aiRes; while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { + CNetAddr resolved; if (aiTrav->ai_family == AF_INET) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); - vIP.emplace_back(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr); + resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr); } if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); - vIP.emplace_back(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr); + struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr; + resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id); + } + /* Never allow resolving to an internal address. Consider any such result invalid */ + if (!resolved.IsInternal()) { + vIP.push_back(resolved); } aiTrav = aiTrav->ai_next; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 110fae714870..3b96c0b280f1 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -343,7 +343,7 @@ static UniValue GetNetworksInfo() UniValue networks(UniValue::VARR); for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast(n); - if (network == NET_UNROUTABLE) + if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue; proxyType proxy; UniValue obj(UniValue::VOBJ); diff --git a/src/serialize.h b/src/serialize.h index aa3e60b7cea9..dde4883be959 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -535,7 +535,7 @@ class LimitedString } string.resize(size); if (size != 0) - s.read((char*)&string[0], size); + s.read((char*)string.data(), size); } template @@ -543,7 +543,7 @@ class LimitedString { WriteCompactSize(s, string.size()); if (!string.empty()) - s.write((char*)&string[0], string.size()); + s.write((char*)string.data(), string.size()); } }; @@ -740,7 +740,7 @@ void Serialize(Stream& os, const std::basic_string& str) { WriteCompactSize(os, str.size()); if (!str.empty()) - os.write((char*)&str[0], str.size() * sizeof(str[0])); + os.write((char*)str.data(), str.size() * sizeof(C)); } template @@ -749,7 +749,7 @@ void Unserialize(Stream& is, std::basic_string& str) unsigned int nSize = ReadCompactSize(is); str.resize(nSize); if (nSize != 0) - is.read((char*)&str[0], nSize * sizeof(str[0])); + is.read((char*)str.data(), nSize * sizeof(C)); } /** @@ -798,7 +798,7 @@ void Serialize_impl(Stream& os, const prevector& v, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); + os.write((char*)v.data(), v.size() * sizeof(T)); } template @@ -866,7 +866,7 @@ void Serialize_impl(Stream& os, const std::vector& v, const unsigned char& { WriteCompactSize(os, v.size()); if (!v.empty()) - os.write((char*)&v[0], v.size() * sizeof(T)); + os.write((char*)v.data(), v.size() * sizeof(T)); } template diff --git a/src/streams.h b/src/streams.h index 10df39862f24..9a2198aa030b 100644 --- a/src/streams.h +++ b/src/streams.h @@ -267,7 +267,7 @@ class CBaseDataStream { // Special case: stream << stream concatenates like stream += stream if (!vch.empty()) - s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); + s.write((char*)vch.data(), vch.size() * sizeof(value_type)); } template diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index c33fdb6a7e80..a2af0fbec908 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -9,6 +9,7 @@ #include "netbase.h" #include "serialize.h" #include "streams.h" +#include "util/memory.h" #include "test/test_pivx.h" @@ -176,4 +177,42 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_CHECK(pnode2->fFeeler == false); } +// prior to PR #14728, this test triggers an undefined behavior +BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) +{ + // set up local addresses; all that's necessary to reproduce the bug is + // that a normal IPv4 address is among the entries, but if this address is + // !IsRoutable the undefined behavior is easier to trigger deterministically + { + LOCK(cs_mapLocalHost); + in_addr ipv4AddrLocal; + ipv4AddrLocal.s_addr = 0x0100007f; + CNetAddr addr = CNetAddr(ipv4AddrLocal); + LocalServiceInfo lsi; + lsi.nScore = 23; + lsi.nPort = 42; + mapLocalHost[addr] = lsi; + } + + // create a peer with an IPv4 address + in_addr ipv4AddrPeer; + ipv4AddrPeer.s_addr = 0xa0b0c001; + CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); + std::unique_ptr pnode = MakeUnique(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, std::string{}, false); + pnode->fSuccessfullyConnected.store(true); + + // the peer claims to be reaching us via IPv6 + in6_addr ipv6AddrLocal; + memset(ipv6AddrLocal.s6_addr, 0, 16); + ipv6AddrLocal.s6_addr[0] = 0xcc; + CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK); + pnode->SetAddrLocal(addrLocal); + + // before patch, this causes undefined behavior detectable with clang's -fsanitize=memory + AdvertiseLocal(&*pnode); + + // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer + BOOST_CHECK(1); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 7b03a7bc0632..6c0ff70d95b3 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -29,6 +29,13 @@ static CSubNet ResolveSubNet(const char* subnet) return ret; } +static CNetAddr CreateInternal(const char* host) +{ + CNetAddr addr; + addr.SetInternal(host); + return addr; +} + BOOST_AUTO_TEST_CASE(netbase_networks) { BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE); @@ -36,6 +43,7 @@ BOOST_AUTO_TEST_CASE(netbase_networks) BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4); BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6); BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR); + BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL); } BOOST_AUTO_TEST_CASE(netbase_properties) @@ -60,6 +68,8 @@ BOOST_AUTO_TEST_CASE(netbase_properties) BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable()); BOOST_CHECK(ResolveIP("2001::1").IsRoutable()); BOOST_CHECK(ResolveIP("127.0.0.1").IsValid()); + BOOST_CHECK(CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal()); + BOOST_CHECK(CreateInternal("bar.com").IsInternal()); } bool static TestSplitHost(std::string test, std::string host, int port) @@ -104,6 +114,11 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) BOOST_CHECK(TestParse("[::]:51472", "[::]:51472")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); BOOST_CHECK(TestParse(":::", "[::]:0")); + + // verify that an internal address fails to resolve + BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0")); + // and that a one-off resolves correctly + BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535")); } BOOST_AUTO_TEST_CASE(onioncat_test) @@ -302,6 +317,10 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup) BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == std::vector({(unsigned char)NET_TOR, 239})); // Tor BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == std::vector({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == std::vector({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6 + + // baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505 + std::vector internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07}; + BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group); } BOOST_AUTO_TEST_CASE(netbase_parsenetwork) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index c0439091852c..53d97548b858 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -663,7 +663,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro // _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2)); cookie = std::vector(status_cookie.second.begin(), status_cookie.second.end()); clientNonce = std::vector(TOR_NONCE_SIZE, 0); - GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE); + GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE); _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { if (status_cookie.first) { diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 4a8f6adb5d4b..96d5d60465a9 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -190,7 +190,7 @@ std::vector DecodeBase64(const char* p, bool* pfInvalid) std::string DecodeBase64(const std::string& str) { std::vector vchRet = DecodeBase64(str.c_str()); - return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); + return std::string((const char*)vchRet.data(), vchRet.size()); } // Base64 encoding with secure memory allocation @@ -286,7 +286,7 @@ std::vector DecodeBase32(const char* p, bool* pfInvalid) std::string DecodeBase32(const std::string& str) { std::vector vchRet = DecodeBase32(str.c_str()); - return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); + return std::string((const char*)vchRet.data(), vchRet.size()); } static bool ParsePrechecks(const std::string& str)