diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -454,6 +454,7 @@ bitcoin_seeder_LDADD = \ $(LIBBITCOIN_SEEDER) \ + $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -3,7 +3,7 @@ #include "protocol.h" -bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, - int &blocks, std::vector *vAddr); +bool TestNode(const CSeederService &cip, int &ban, int &client, + std::string &clientSV, int &blocks, std::vector *vAddr); #endif diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp --- a/src/seeder/bitcoin.cpp +++ b/src/seeder/bitcoin.cpp @@ -89,7 +89,7 @@ int64_t nTime = time(nullptr); uint64_t nLocalNonce = BITCOIN_SEED_NONCE; int64_t nLocalServices = 0; - CAddress me(CService("0.0.0.0")); + CAddress me(CSeederService("0.0.0.0")); BeginMessage("version"); int nBestHeight = GetRequireHeight(); std::string ver = "/bitcoin-cash-seeder:0.15/"; @@ -231,7 +231,7 @@ } public: - CNode(const CService &ip, std::vector *vAddrIn) + CNode(const CSeederService &ip, std::vector *vAddrIn) : vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), doneAfter(0), you(ip) { @@ -301,7 +301,7 @@ int GetStartingHeight() { return nStartingHeight; } }; -bool TestNode(const CService &cip, int &ban, int &clientV, +bool TestNode(const CSeederService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, std::vector *vAddr) { try { @@ -325,7 +325,7 @@ /* int main(void) { - CService ip("bitcoin.sipa.be", 8333, true); + CSeederService ip("bitcoin.sipa.be", 8333, true); std::vector vAddr; vAddr.clear(); int ban = 0; diff --git a/src/seeder/db.h b/src/seeder/db.h --- a/src/seeder/db.h +++ b/src/seeder/db.h @@ -22,7 +22,7 @@ return testnet ? 500000 : 350000; } -static inline std::string ToString(const CService &ip) { +static inline std::string ToString(const CSeederService &ip) { std::string str = ip.ToString(); while (str.size() < 22) { str += ' '; @@ -60,7 +60,7 @@ class CAddrReport { public: - CService ip; + CSeederService ip; int clientVersion; int blocks; double uptime[5]; @@ -72,7 +72,7 @@ class CAddrInfo { private: - CService ip; + CSeederService ip; uint64_t services; int64_t lastTry; int64_t ourLastTry; @@ -223,8 +223,8 @@ int nAge; }; -struct CServiceResult { - CService service; +struct CSeederServiceResult { + CSeederService service; bool fGood; int nBanTime; int nHeight; @@ -250,7 +250,7 @@ // map address id to address info (b,c,d,e) std::map idToInfo; // map ip to id (b,c,d,e) - std::map ipToId; + std::map ipToId; // sequence of tried nodes, in order we have tried connecting to them (c,d) std::deque ourId; // set of nodes not yet tried (b) @@ -265,25 +265,25 @@ void Add_(const CAddress &addr, bool force); // get an IP to test (must call Good_, Bad_, or Skipped_ on result // afterwards) - bool Get_(CServiceResult &ip, int &wait); - bool GetMany_(std::vector &ips, int max, int &wait); + bool Get_(CSeederServiceResult &ip, int &wait); + bool GetMany_(std::vector &ips, int max, int &wait); // mark an IP as good (must have been returned by Get_) - void Good_(const CService &ip, int clientV, std::string clientSV, + void Good_(const CSeederService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as bad (and optionally ban it) (must have been returned by // Get_) - void Bad_(const CService &ip, int ban); + void Bad_(const CSeederService &ip, int ban); // mark an IP as skipped (must have been returned by Get_) - void Skipped_(const CService &ip); + void Skipped_(const CSeederService &ip); // look up id of an IP - int Lookup_(const CService &ip); + int Lookup_(const CSeederService &ip); // get a random set of IPs (shared lock only) void GetIPs_(std::set &ips, uint64_t requestedFlags, uint32_t max, const bool *nets); public: // nodes that are banned, with their unban time (a) - std::map banned; + std::map banned; void GetStats(CAddrDbStats &stats) { LOCK(cs); @@ -388,31 +388,31 @@ } } - void Good(const CService &addr, int clientVersion, + void Good(const CSeederService &addr, int clientVersion, std::string clientSubVersion, int blocks) { LOCK(cs); Good_(addr, clientVersion, clientSubVersion, blocks); } - void Skipped(const CService &addr) { + void Skipped(const CSeederService &addr) { LOCK(cs); Skipped_(addr); } - void Bad(const CService &addr, int ban = 0) { + void Bad(const CSeederService &addr, int ban = 0) { LOCK(cs); Bad_(addr, ban); } - bool Get(CServiceResult &ip, int &wait) { + bool Get(CSeederServiceResult &ip, int &wait) { LOCK(cs); return Get_(ip, wait); } - void GetMany(std::vector &ips, int max, int &wait) { + void GetMany(std::vector &ips, int max, int &wait) { LOCK(cs); while (max > 0) { - CServiceResult ip = {}; + CSeederServiceResult ip = {}; if (!Get_(ip, wait)) { return; } @@ -421,7 +421,7 @@ } } - void ResultMany(const std::vector &ips) { + void ResultMany(const std::vector &ips) { LOCK(cs); for (size_t i = 0; i < ips.size(); i++) { if (ips[i].fGood) { diff --git a/src/seeder/db.cpp b/src/seeder/db.cpp --- a/src/seeder/db.cpp +++ b/src/seeder/db.cpp @@ -34,7 +34,7 @@ // stat1W.weight), stat1W.count); } -bool CAddrDb::Get_(CServiceResult &ip, int &wait) { +bool CAddrDb::Get_(CSeederServiceResult &ip, int &wait) { int64_t now = time(nullptr); size_t tot = unkId.size() + ourId.size(); if (tot == 0) { @@ -72,13 +72,13 @@ return true; } -int CAddrDb::Lookup_(const CService &ip) { +int CAddrDb::Lookup_(const CSeederService &ip) { if (ipToId.count(ip)) return ipToId[ip]; return -1; } -void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, - int blocks) { +void CAddrDb::Good_(const CSeederService &addr, int clientV, + std::string clientSV, int blocks) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); @@ -97,7 +97,7 @@ ourId.push_back(id); } -void CAddrDb::Bad_(const CService &addr, int ban) { +void CAddrDb::Bad_(const CSeederService &addr, int ban) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); @@ -126,7 +126,7 @@ nDirty++; } -void CAddrDb::Skipped_(const CService &addr) { +void CAddrDb::Skipped_(const CSeederService &addr) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); @@ -139,7 +139,7 @@ if (!force && !addr.IsRoutable()) { return; } - CService ipp(addr); + CSeederService ipp(addr); if (banned.count(ipp)) { time_t bantime = banned[ipp]; if (force || (bantime < time(nullptr) && addr.nTime > bantime)) { @@ -221,7 +221,7 @@ } for (auto &id : ids) { - CService &ip = idToInfo[id].ip; + CSeederService &ip = idToInfo[id].ip; if (nets[ip.GetNetwork()]) { ips.insert(ip); } diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -172,7 +172,7 @@ extern "C" void *ThreadCrawler(void *data) { int *nThreads = (int *)data; do { - std::vector ips; + std::vector ips; int wait = 5; db.GetMany(ips, 16, wait); int64_t now = time(nullptr); @@ -185,7 +185,7 @@ std::vector addr; for (size_t i = 0; i < ips.size(); i++) { - CServiceResult &res = ips[i]; + CSeederServiceResult &res = ips[i]; res.nBanTime = 0; res.nClientV = 0; res.nHeight = 0; @@ -452,14 +452,14 @@ extern "C" void *ThreadSeeder(void *) { if (!fTestNet) { - db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true); + db.Add(CSeederService("kjy2eqzk4zwi5zd3.onion", 8333), true); } do { for (int i = 0; seeds[i] != ""; i++) { std::vector ips; LookupHost(seeds[i].c_str(), ips); for (auto &ip : ips) { - db.Add(CService(ip, GetDefaultPort()), true); + db.Add(CSeederService(ip, GetDefaultPort()), true); } } Sleep(1800000); @@ -482,14 +482,14 @@ } printf("\n"); if (opts.tor) { - CService service(opts.tor, 9050); + CSeederService service(opts.tor, 9050); if (service.IsValid()) { printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_TOR, service); } } if (opts.ipv4_proxy) { - CService service(opts.ipv4_proxy, 9050); + CSeederService service(opts.ipv4_proxy, 9050); if (service.IsValid()) { printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); @@ -497,7 +497,7 @@ } } if (opts.ipv6_proxy) { - CService service(opts.ipv6_proxy, 9050); + CSeederService service(opts.ipv6_proxy, 9050); if (service.IsValid()) { printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); diff --git a/src/seeder/netbase.h b/src/seeder/netbase.h --- a/src/seeder/netbase.h +++ b/src/seeder/netbase.h @@ -5,6 +5,7 @@ #define BITCOIN_SEEDER_NETBASE_H #include "compat.h" +#include "netaddress.h" #include "serialize.h" #include @@ -18,115 +19,48 @@ #undef SetPort #endif -enum Network { - NET_UNROUTABLE, - NET_IPV4, - NET_IPV6, - NET_TOR, - NET_I2P, - - NET_MAX, -}; - extern int nConnectTimeout; extern bool fNameLookup; -/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ -class CNetAddr { -protected: - uint8_t ip[16]; // in network byte order - -public: - CNetAddr(); - CNetAddr(const struct in_addr &ipv4Addr); - explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); - explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); - void Init(); - void SetIP(const CNetAddr &ip); - bool SetSpecial(const std::string &strName); // for Tor and I2P 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/I2P) - bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot - bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, - // 192.168.0.0/16, 172.16.0.0/12) - bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) - bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) - bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) - bool IsRFC4193() const; // IPv6 unique local (FC00::/15) - bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) - bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) - bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) - bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) - bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) - bool IsTor() const; - bool IsI2P() const; - bool IsLocal() const; - bool IsRoutable() const; - bool IsValid() const; - bool IsMulticast() const; - enum Network GetNetwork() const; - std::string ToString() const; - std::string ToStringIP() const; - unsigned int GetByte(int n) const; - uint64_t GetHash() const; - bool GetInAddr(struct in_addr *pipv4Addr) const; - std::vector GetGroup() const; - int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const; - void print() const; - - CNetAddr(const struct in6_addr &pipv6Addr); - bool GetIn6Addr(struct in6_addr *pipv6Addr) const; - - friend bool operator==(const CNetAddr &a, const CNetAddr &b); - friend bool operator!=(const CNetAddr &a, const CNetAddr &b); - friend bool operator<(const CNetAddr &a, const CNetAddr &b); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(FLATDATA(ip)); - } -}; - /** A combination of a network address (CNetAddr) and a (TCP) port */ -class CService : public CNetAddr { +class CSeederService : public CNetAddr { protected: unsigned short port; // host order public: - CService(); - CService(const CNetAddr &ip, unsigned short port); - CService(const struct in_addr &ipv4Addr, unsigned short port); - CService(const struct sockaddr_in &addr); - explicit CService(const char *pszIpPort, int portDefault, - bool fAllowLookup = false); - explicit CService(const char *pszIpPort, bool fAllowLookup = false); - explicit CService(const std::string &strIpPort, int portDefault, - bool fAllowLookup = false); - explicit CService(const std::string &strIpPort, bool fAllowLookup = false); + CSeederService(); + CSeederService(const CNetAddr &ip, unsigned short port); + CSeederService(const struct in_addr &ipv4Addr, unsigned short port); + CSeederService(const struct sockaddr_in &addr); + explicit CSeederService(const char *pszIpPort, int portDefault, + bool fAllowLookup = false); + explicit CSeederService(const char *pszIpPort, bool fAllowLookup = false); + explicit CSeederService(const std::string &strIpPort, int portDefault, + bool fAllowLookup = false); + explicit CSeederService(const std::string &strIpPort, + bool fAllowLookup = false); void Init(); void SetPort(unsigned short portIn); unsigned short GetPort() const; bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const; bool SetSockAddr(const struct sockaddr *paddr); - friend bool operator==(const CService &a, const CService &b); - friend bool operator!=(const CService &a, const CService &b); - friend bool operator<(const CService &a, const CService &b); + friend bool operator==(const CSeederService &a, const CSeederService &b); + friend bool operator!=(const CSeederService &a, const CSeederService &b); + friend bool operator<(const CSeederService &a, const CSeederService &b); std::vector GetKey() const; std::string ToString() const; std::string ToStringPort() const; std::string ToStringIPPort() const; void print() const; - CService(const struct in6_addr &ipv6Addr, unsigned short port); - CService(const struct sockaddr_in6 &addr); + CSeederService(const struct in6_addr &ipv6Addr, unsigned short port); + CSeederService(const struct sockaddr_in6 &addr); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { - CService *pthis = const_cast(this); + CSeederService *pthis = const_cast(this); READWRITE(FLATDATA(ip)); unsigned short portN = htons(port); READWRITE(portN); @@ -138,24 +72,26 @@ 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 GetProxy(enum Network net, CService &addrProxy); +bool SetProxy(enum Network net, CSeederService addrProxy, + int nSocksVersion = 5); +bool GetProxy(enum Network net, CSeederService &addrProxy); bool IsProxy(const CNetAddr &addr); -bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); +bool SetNameProxy(CSeederService addrProxy, int nSocksVersion = 5); bool GetNameProxy(); bool LookupHost(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHostNumeric(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0); -bool Lookup(const char *pszName, CService &addr, int portDefault = 0, +bool Lookup(const char *pszName, CSeederService &addr, int portDefault = 0, bool fAllowLookup = true); -bool Lookup(const char *pszName, std::vector &vAddr, +bool Lookup(const char *pszName, std::vector &vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); -bool LookupNumeric(const char *pszName, CService &addr, int portDefault = 0); -bool ConnectSocket(const CService &addr, SOCKET &hSocketRet, +bool LookupNumeric(const char *pszName, CSeederService &addr, + int portDefault = 0); +bool ConnectSocket(const CSeederService &addr, SOCKET &hSocketRet, int nTimeout = nConnectTimeout); -bool ConnectSocketByName(CService &addr, SOCKET &hSocketRet, +bool ConnectSocketByName(CSeederService &addr, SOCKET &hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); diff --git a/src/seeder/netbase.cpp b/src/seeder/netbase.cpp --- a/src/seeder/netbase.cpp +++ b/src/seeder/netbase.cpp @@ -16,7 +16,7 @@ #define printf my_printf // Settings -typedef std::pair proxyType; +typedef std::pair proxyType; static proxyType proxyInfo[NET_MAX]; static proxyType nameproxyInfo; int nConnectTimeout = 5000; @@ -29,7 +29,6 @@ if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "tor") return NET_TOR; - if (net == "i2p") return NET_I2P; return NET_UNROUTABLE; } @@ -127,8 +126,8 @@ return LookupHost(pszName, vIP, nMaxSolutions, false); } -bool Lookup(const char *pszName, std::vector &vAddr, int portDefault, - bool fAllowLookup, unsigned int nMaxSolutions) { +bool Lookup(const char *pszName, std::vector &vAddr, + int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) { if (pszName[0] == 0) return false; int port = portDefault; std::string hostname = ""; @@ -140,24 +139,24 @@ if (!fRet) return false; vAddr.resize(vIP.size()); for (unsigned int i = 0; i < vIP.size(); i++) - vAddr[i] = CService(vIP[i], port); + vAddr[i] = CSeederService(vIP[i], port); return true; } -bool Lookup(const char *pszName, CService &addr, int portDefault, +bool Lookup(const char *pszName, CSeederService &addr, int portDefault, bool fAllowLookup) { - std::vector vService; + std::vector vService; bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); if (!fRet) return false; addr = vService[0]; return true; } -bool LookupNumeric(const char *pszName, CService &addr, int portDefault) { +bool LookupNumeric(const char *pszName, CSeederService &addr, int portDefault) { return Lookup(pszName, addr, portDefault, false); } -static bool Socks4(const CService &addrDest, SOCKET &hSocket) { +static bool Socks4(const CSeederService &addrDest, SOCKET &hSocket) { printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); if (!addrDest.IsIPv4()) { closesocket(hSocket); @@ -299,7 +298,7 @@ return true; } -static bool ConnectSocketDirectly(const CService &addrConnect, +static bool ConnectSocketDirectly(const CSeederService &addrConnect, SOCKET &hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; @@ -406,7 +405,7 @@ return true; } -bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { +bool SetProxy(enum Network net, CSeederService addrProxy, int nSocksVersion) { assert(net >= 0 && net < NET_MAX); if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) return false; @@ -415,14 +414,14 @@ return true; } -bool GetProxy(enum Network net, CService &addrProxy) { +bool GetProxy(enum Network net, CSeederService &addrProxy) { assert(net >= 0 && net < NET_MAX); if (!proxyInfo[net].second) return false; addrProxy = proxyInfo[net].first; return true; } -bool SetNameProxy(CService addrProxy, int nSocksVersion) { +bool SetNameProxy(CSeederService addrProxy, int nSocksVersion) { if (nSocksVersion != 0 && nSocksVersion != 5) return false; if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); @@ -441,7 +440,8 @@ return false; } -bool ConnectSocket(const CService &addrDest, SOCKET &hSocketRet, int nTimeout) { +bool ConnectSocket(const CSeederService &addrDest, SOCKET &hSocketRet, + int nTimeout) { const proxyType &proxy = proxyInfo[addrDest.GetNetwork()]; // no proxy needed @@ -470,20 +470,23 @@ return true; } -bool ConnectSocketByName(CService &addr, SOCKET &hSocketRet, +bool ConnectSocketByName(CSeederService &addr, SOCKET &hSocketRet, const char *pszDest, int portDefault, int nTimeout) { std::string strDest; int port = portDefault; SplitHostPort(std::string(pszDest), port, strDest); SOCKET hSocket = INVALID_SOCKET; - CService addrResolved( - CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port); - if (addrResolved.IsValid()) { - addr = addrResolved; - return ConnectSocket(addr, hSocketRet, nTimeout); + CSeederService addrResolved; + if (Lookup(strDest.c_str(), addrResolved, port, + fNameLookup && !nameproxyInfo.second)) { + if (addrResolved.IsValid()) { + addr = addrResolved; + return ConnectSocket(addr, hSocketRet, nTimeout); + } } - addr = CService("0.0.0.0:0"); + + addr = CSeederService("0.0.0.0:0"); if (!nameproxyInfo.second) return false; if (!ConnectSocketDirectly(nameproxyInfo.first, hSocket, nTimeout)) return false; @@ -501,514 +504,94 @@ return true; } -void CNetAddr::Init() { - memset(ip, 0, 16); -} - -void CNetAddr::SetIP(const CNetAddr &ipIn) { - memcpy(ip, ipIn.ip, sizeof(ip)); -} - -static const uint8_t pchOnionCat[] = {0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43}; -static const uint8_t pchGarliCat[] = {0xFD, 0x60, 0xDB, 0x4D, 0xDD, 0xB5}; - -bool CNetAddr::SetSpecial(const std::string &strName) { - if (strName.size() > 6 && - strName.substr(strName.size() - 6, 6) == ".onion") { - std::vector vchAddr = - DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); - if (vchAddr.size() != 16 - sizeof(pchOnionCat)) return false; - memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); - for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) - ip[i + sizeof(pchOnionCat)] = vchAddr[i]; - return true; - } - if (strName.size() > 11 && - strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") { - std::vector vchAddr = - DecodeBase32(strName.substr(0, strName.size() - 11).c_str()); - if (vchAddr.size() != 16 - sizeof(pchGarliCat)) return false; - memcpy(ip, pchOnionCat, sizeof(pchGarliCat)); - for (unsigned int i = 0; i < 16 - sizeof(pchGarliCat); i++) - ip[i + sizeof(pchGarliCat)] = vchAddr[i]; - return true; - } - return false; -} - -CNetAddr::CNetAddr() { - Init(); -} - -CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) { - memcpy(ip, pchIPv4, 12); - memcpy(ip + 12, &ipv4Addr, 4); -} - -CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr) { - memcpy(ip, &ipv6Addr, 16); -} - -CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) { - Init(); - std::vector vIP; - if (LookupHost(pszIp, vIP, 1, fAllowLookup)) *this = vIP[0]; -} - -CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) { - Init(); - std::vector vIP; - if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) *this = vIP[0]; -} - -unsigned int CNetAddr::GetByte(int n) const { - return ip[15 - n]; -} - -bool CNetAddr::IsIPv4() const { - return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); -} - -bool CNetAddr::IsIPv6() const { - return (!IsIPv4() && !IsTor() && !IsI2P()); -} - -bool CNetAddr::IsRFC1918() const { - return IsIPv4() && - (GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || - (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); -} - -bool CNetAddr::IsReserved() const { - return IsIPv4() && (GetByte(3) >= 240); -} - -bool CNetAddr::IsRFC3927() const { - return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); -} - -bool CNetAddr::IsRFC3849() const { - return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && - GetByte(12) == 0xB8; -} - -bool CNetAddr::IsRFC3964() const { - return (GetByte(15) == 0x20 && GetByte(14) == 0x02); -} - -bool CNetAddr::IsRFC6052() const { - static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0, - 0, 0, 0, 0, 0, 0}; - return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); -} - -bool CNetAddr::IsRFC4380() const { - return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && - GetByte(12) == 0); -} - -bool CNetAddr::IsRFC4862() const { - static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0}; - return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); -} - -bool CNetAddr::IsRFC4193() const { - return ((GetByte(15) & 0xFE) == 0xFC); -} - -bool CNetAddr::IsRFC6145() const { - static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0, - 0, 0, 0xFF, 0xFF, 0, 0}; - return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); -} - -bool CNetAddr::IsRFC4843() const { - return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && - (GetByte(12) & 0xF0) == 0x10); -} - -bool CNetAddr::IsTor() const { - return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); -} - -bool CNetAddr::IsI2P() const { - return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); -} - -bool CNetAddr::IsLocal() const { - // IPv4 loopback - if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) return true; - - // IPv6 loopback (::1/128) - static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1}; - if (memcmp(ip, pchLocal, 16) == 0) return true; - - return false; -} - -bool CNetAddr::IsMulticast() const { - return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) || (GetByte(15) == 0xFF); -} - -bool CNetAddr::IsValid() const { - // Cleanup 3-byte shifted addresses caused by garbage in size field - // of addr messages from versions before 0.2.9 checksum. - // Two consecutive addr messages look like this: - // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 - // addr26 addr26... - // so if the first length field is garbled, it reads the second batch - // of addr misaligned by 3 bytes. - if (memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) return false; - - // unspecified IPv6 address (::/128) - uint8_t ipNone[16] = {}; - if (memcmp(ip, ipNone, 16) == 0) return false; - - // documentation IPv6 address - if (IsRFC3849()) return false; - - if (IsIPv4()) { - // INADDR_NONE - uint32_t ipNone = INADDR_NONE; - if (memcmp(ip + 12, &ipNone, 4) == 0) return false; - - // 0 - ipNone = 0; - if (memcmp(ip + 12, &ipNone, 4) == 0) return false; - } - - return true; -} - -bool CNetAddr::IsRoutable() const { - return IsValid() && - !(IsReserved() || IsRFC1918() || IsRFC3927() || IsRFC4862() || - (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal()); -} - -enum Network CNetAddr::GetNetwork() const { - if (!IsRoutable()) return NET_UNROUTABLE; - - if (IsIPv4()) return NET_IPV4; - - if (IsTor()) return NET_TOR; - - if (IsI2P()) return NET_I2P; - - return NET_IPV6; -} - -std::string CNetAddr::ToStringIP() const { - if (IsTor()) return EncodeBase32(&ip[6], 10) + ".onion"; - if (IsI2P()) return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p"; - CService serv(*this, 0); - struct sockaddr_storage sockaddr; - socklen_t socklen = sizeof(sockaddr); - if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) { - char name[1025] = ""; - if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name, - sizeof(name), nullptr, 0, NI_NUMERICHOST)) - return std::string(name); - } - - if (IsIPv4()) { - return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), - GetByte(0)); - } - - return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14), - GetByte(13) << 8 | GetByte(12), - GetByte(11) << 8 | GetByte(10), - GetByte(9) << 8 | GetByte(8), GetByte(7) << 8 | GetByte(6), - GetByte(5) << 8 | GetByte(4), GetByte(3) << 8 | GetByte(2), - GetByte(1) << 8 | GetByte(0)); -} - -std::string CNetAddr::ToString() const { - return ToStringIP(); -} - -bool operator==(const CNetAddr &a, const CNetAddr &b) { - return (memcmp(a.ip, b.ip, 16) == 0); -} - -bool operator!=(const CNetAddr &a, const CNetAddr &b) { - return (memcmp(a.ip, b.ip, 16) != 0); -} - -bool operator<(const CNetAddr &a, const CNetAddr &b) { - return (memcmp(a.ip, b.ip, 16) < 0); -} - -bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { - if (!IsIPv4()) return false; - memcpy(pipv4Addr, ip + 12, 4); - return true; -} - -bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { - memcpy(pipv6Addr, ip, 16); - return true; -} - -// get canonical identifier of an address' group -// no two connections will be attempted to addresses with the same group -std::vector CNetAddr::GetGroup() const { - std::vector vchRet; - int nClass = NET_IPV6; - int nStartByte = 0; - int nBits = 16; - - // all local addresses belong to the same group - if (IsLocal()) { - nClass = 255; - nBits = 0; - } - - // all unroutable addresses belong to the same group - if (!IsRoutable()) { - nClass = NET_UNROUTABLE; - nBits = 0; - } - // for IPv4 addresses, '1' + the 16 higher-order bits of the IP - // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix - else if (IsIPv4() || IsRFC6145() || IsRFC6052()) { - nClass = NET_IPV4; - nStartByte = 12; - } - // for 6to4 tunnelled addresses, use the encapsulated IPv4 address - else if (IsRFC3964()) { - nClass = NET_IPV4; - nStartByte = 2; - } - // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address - else if (IsRFC4380()) { - vchRet.push_back(NET_IPV4); - vchRet.push_back(GetByte(3) ^ 0xFF); - vchRet.push_back(GetByte(2) ^ 0xFF); - return vchRet; - } else if (IsTor()) { - nClass = NET_TOR; - nStartByte = 6; - nBits = 4; - } else if (IsI2P()) { - nClass = NET_I2P; - nStartByte = 6; - nBits = 4; - } else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && - GetByte(13) == 0x04 && GetByte(12) == 0x70) { - // for he.net, use /36 groups - nBits = 36; - } else { - // for the rest of the IPv6 network, use /32 groups - nBits = 32; - } - - vchRet.push_back(nClass); - while (nBits >= 8) { - vchRet.push_back(GetByte(15 - nStartByte)); - nStartByte++; - nBits -= 8; - } - if (nBits > 0) - vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1)); - - return vchRet; -} - -uint64_t CNetAddr::GetHash() const { - uint256 hash = Hash(&ip[0], &ip[16]); - uint64_t nRet; - memcpy(&nRet, &hash, sizeof(nRet)); - return nRet; -} - -void CNetAddr::print() const { - printf("CNetAddr(%s)\n", ToString().c_str()); -} - -// private extensions to enum Network, only returned by GetExtNetwork, -// and only used in GetReachabilityFrom -static const int NET_UNKNOWN = NET_MAX + 0; -static const int NET_TEREDO = NET_MAX + 1; -static int GetExtNetwork(const CNetAddr *addr) { - if (addr == nullptr) return NET_UNKNOWN; - if (addr->IsRFC4380()) return NET_TEREDO; - return addr->GetNetwork(); -} - -/** Calculates a metric for how reachable (*this) is from a given partner */ -int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { - enum Reachability { - REACH_UNREACHABLE, - REACH_DEFAULT, - REACH_TEREDO, - REACH_IPV6_WEAK, - REACH_IPV4, - REACH_IPV6_STRONG, - REACH_PRIVATE - }; - - if (!IsRoutable()) return REACH_UNREACHABLE; - - int ourNet = GetExtNetwork(this); - int theirNet = GetExtNetwork(paddrPartner); - bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); - - switch (theirNet) { - case NET_IPV4: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_IPV4: - return REACH_IPV4; - } - case NET_IPV6: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_TEREDO: - return REACH_TEREDO; - case NET_IPV4: - return REACH_IPV4; - case NET_IPV6: - // only prefer giving our IPv6 address if it's not tunnelled - return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; - } - case NET_TOR: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_IPV4: - // Tor users can connect to IPv4 as well - return REACH_IPV4; - case NET_TOR: - return REACH_PRIVATE; - } - case NET_I2P: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_I2P: - return REACH_PRIVATE; - } - case NET_TEREDO: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_TEREDO: - return REACH_TEREDO; - case NET_IPV6: - return REACH_IPV6_WEAK; - case NET_IPV4: - return REACH_IPV4; - } - case NET_UNKNOWN: - case NET_UNROUTABLE: - default: - switch (ourNet) { - default: - return REACH_DEFAULT; - case NET_TEREDO: - return REACH_TEREDO; - case NET_IPV6: - return REACH_IPV6_WEAK; - case NET_IPV4: - return REACH_IPV4; - case NET_I2P: - // assume connections from unroutable addresses are - return REACH_PRIVATE; - case NET_TOR: - // either from Tor/I2P, or don't care about our address - return REACH_PRIVATE; - } - } -} - -void CService::Init() { +void CSeederService::Init() { port = 0; } -CService::CService() { +CSeederService::CSeederService() { Init(); } -CService::CService(const CNetAddr &cip, unsigned short portIn) +CSeederService::CSeederService(const CNetAddr &cip, unsigned short portIn) : CNetAddr(cip), port(portIn) {} -CService::CService(const struct in_addr &ipv4Addr, unsigned short portIn) +CSeederService::CSeederService(const struct in_addr &ipv4Addr, + unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) {} -CService::CService(const struct in6_addr &ipv6Addr, unsigned short portIn) +CSeederService::CSeederService(const struct in6_addr &ipv6Addr, + unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) {} -CService::CService(const struct sockaddr_in &addr) +CSeederService::CSeederService(const struct sockaddr_in &addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) { assert(addr.sin_family == AF_INET); } -CService::CService(const struct sockaddr_in6 &addr) +CSeederService::CSeederService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) { assert(addr.sin6_family == AF_INET6); } -bool CService::SetSockAddr(const struct sockaddr *paddr) { +bool CSeederService::SetSockAddr(const struct sockaddr *paddr) { switch (paddr->sa_family) { case AF_INET: - *this = CService(*(const struct sockaddr_in *)paddr); + *this = CSeederService(*(const struct sockaddr_in *)paddr); return true; case AF_INET6: - *this = CService(*(const struct sockaddr_in6 *)paddr); + *this = CSeederService(*(const struct sockaddr_in6 *)paddr); return true; default: return false; } } -CService::CService(const char *pszIpPort, bool fAllowLookup) { +CSeederService::CSeederService(const char *pszIpPort, bool fAllowLookup) { Init(); - CService ip; + CSeederService ip; if (Lookup(pszIpPort, ip, 0, fAllowLookup)) *this = ip; } -CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) { +CSeederService::CSeederService(const char *pszIpPort, int portDefault, + bool fAllowLookup) { Init(); - CService ip; + CSeederService ip; if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) *this = ip; } -CService::CService(const std::string &strIpPort, bool fAllowLookup) { +CSeederService::CSeederService(const std::string &strIpPort, + bool fAllowLookup) { Init(); - CService ip; + CSeederService ip; if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) *this = ip; } -CService::CService(const std::string &strIpPort, int portDefault, - bool fAllowLookup) { +CSeederService::CSeederService(const std::string &strIpPort, int portDefault, + bool fAllowLookup) { Init(); - CService ip; + CSeederService ip; if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) *this = ip; } -unsigned short CService::GetPort() const { +unsigned short CSeederService::GetPort() const { return port; } -bool operator==(const CService &a, const CService &b) { +bool operator==(const CSeederService &a, const CSeederService &b) { return (CNetAddr)a == (CNetAddr)b && a.port == b.port; } -bool operator!=(const CService &a, const CService &b) { +bool operator!=(const CSeederService &a, const CSeederService &b) { return (CNetAddr)a != (CNetAddr)b || a.port != b.port; } -bool operator<(const CService &a, const CService &b) { +bool operator<(const CSeederService &a, const CSeederService &b) { return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); } -bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const { +bool CSeederService::GetSockAddr(struct sockaddr *paddr, + socklen_t *addrlen) const { if (IsIPv4()) { if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) return false; *addrlen = sizeof(struct sockaddr_in); @@ -1032,7 +615,7 @@ return false; } -std::vector CService::GetKey() const { +std::vector CSeederService::GetKey() const { std::vector vKey; vKey.resize(18); memcpy(&vKey[0], ip, 16); @@ -1041,26 +624,26 @@ return vKey; } -std::string CService::ToStringPort() const { +std::string CSeederService::ToStringPort() const { return strprintf("%u", port); } -std::string CService::ToStringIPPort() const { - if (IsIPv4() || IsTor() || IsI2P()) { +std::string CSeederService::ToStringIPPort() const { + if (IsIPv4() || IsTor()) { return ToStringIP() + ":" + ToStringPort(); } else { return "[" + ToStringIP() + "]:" + ToStringPort(); } } -std::string CService::ToString() const { +std::string CSeederService::ToString() const { return ToStringIPPort(); } -void CService::print() const { - printf("CService(%s)\n", ToString().c_str()); +void CSeederService::print() const { + printf("CSeederService(%s)\n", ToString().c_str()); } -void CService::SetPort(unsigned short portIn) { +void CSeederService::SetPort(unsigned short portIn) { port = portIn; } diff --git a/src/seeder/protocol.h b/src/seeder/protocol.h --- a/src/seeder/protocol.h +++ b/src/seeder/protocol.h @@ -67,10 +67,10 @@ NODE_BITCOIN_CASH = (1 << 5), }; -class CAddress : public CService { +class CAddress : public CSeederService { public: CAddress(); - CAddress(CService ipIn, + CAddress(CSeederService ipIn, uint64_t nServicesIn = NODE_NETWORK | NODE_BITCOIN_CASH); void Init(); @@ -81,7 +81,7 @@ inline void SerializationOp(Stream &s, Operation ser_action) { int nVersion = s.GetVersion(); CAddress *pthis = const_cast(this); - CService *pip = (CService *)pthis; + CSeederService *pip = (CSeederService *)pthis; if (ser_action.ForRead()) { pthis->Init(); } diff --git a/src/seeder/protocol.cpp b/src/seeder/protocol.cpp --- a/src/seeder/protocol.cpp +++ b/src/seeder/protocol.cpp @@ -70,11 +70,12 @@ return true; } -CAddress::CAddress() : CService() { +CAddress::CAddress() : CSeederService() { Init(); } -CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn) { +CAddress::CAddress(CSeederService ipIn, uint64_t nServicesIn) + : CSeederService(ipIn) { Init(); nServices = nServicesIn; }