Mercurial > hg > bitcoin
view src/netbase.cpp @ 2477:f8e75c9db98a draft
Preliminary support for Tor/I2P hidden services
There are plans to let Bitcoin function as Tor/I2P hidden service.
To do so, we could use the established encoding provided by OnionCat
and GarliCat (without actually using those tools) to embed Tor/I2P
addresses in IPv6.
This patch makes these addresses considered routable, so they can
travel over the Bitcoin network in 'addr' messages. This will hopefully
make it easier to deploy real hidden service support later.
author | Pieter Wuille <pieter.wuille@gmail.com> |
---|---|
date | Mon, 02 Apr 2012 17:06:11 +0200 |
parents | a9b012461972 |
children | 3513aef58df1 |
line wrap: on
line source
// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "netbase.h" #include "util.h" #ifndef WIN32 #include <sys/fcntl.h> #endif #include "strlcpy.h" using namespace std; // Settings int nSocksVersion = 5; int fUseProxy = false; bool fProxyNameLookup = false; bool fNameLookup = false; CService addrProxy("127.0.0.1",9050); int nConnectTimeout = 5000; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { vIP.clear(); struct addrinfo aiHint; memset(&aiHint, 0, sizeof(struct addrinfo)); aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; #ifdef WIN32 # ifdef USE_IPV6 aiHint.ai_family = AF_UNSPEC; aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; # else aiHint.ai_family = AF_INET; aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; # endif #else # ifdef USE_IPV6 aiHint.ai_family = AF_UNSPEC; aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST); # else aiHint.ai_family = AF_INET; aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST); # endif #endif struct addrinfo *aiRes = NULL; int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); if (nErr) return false; struct addrinfo *aiTrav = aiRes; while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { if (aiTrav->ai_family == AF_INET) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr)); } #ifdef USE_IPV6 if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); } #endif aiTrav = aiTrav->ai_next; } freeaddrinfo(aiRes); return (vIP.size() > 0); } bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { if (pszName[0] == 0) return false; char psz[256]; char *pszHost = psz; strlcpy(psz, pszName, sizeof(psz)); if (psz[0] == '[' && psz[strlen(psz)-1] == ']') { pszHost = psz+1; psz[strlen(psz)-1] = 0; } return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); } bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions) { return LookupHost(pszName, vIP, nMaxSolutions, false); } bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) { if (pszName[0] == 0) return false; int port = portDefault; char psz[256]; char *pszHost = psz; strlcpy(psz, pszName, sizeof(psz)); char* pszColon = strrchr(psz+1,':'); char *pszPortEnd = NULL; int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0; if (pszColon && pszPortEnd && pszPortEnd[0] == 0) { if (psz[0] == '[' && pszColon[-1] == ']') { pszHost = psz+1; pszColon[-1] = 0; } else pszColon[0] = 0; if (port >= 0 && port <= USHRT_MAX) port = portParsed; } else { if (psz[0] == '[' && psz[strlen(psz)-1] == ']') { pszHost = psz+1; psz[strlen(psz)-1] = 0; } } std::vector<CNetAddr> vIP; bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); if (!fRet) return false; vAddr.resize(vIP.size()); for (unsigned int i = 0; i < vIP.size(); i++) vAddr[i] = CService(vIP[i], port); return true; } bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup) { std::vector<CService> 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) { return Lookup(pszName, addr, portDefault, false); } bool static Socks4(const CService &addrDest, SOCKET& hSocket) { printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); 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; addrDest.GetSockAddr(&addr); 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) printf("ERROR: Proxy returned error %d\n", pchRet[1]); return false; } printf("SOCKS4 connected %s\n", addrDest.ToString().c_str()); return true; } bool static Socks5(string strDest, int port, SOCKET& hSocket) { printf("SOCKS5 connecting %s\n", strDest.c_str()); if (strDest.size() > 255) { closesocket(hSocket); return error("Hostname too long"); } char pszSocks5Init[] = "\5\1\0"; char *pszSocks5 = pszSocks5Init; ssize_t nSize = sizeof(pszSocks5Init); ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); if (ret != nSize) { closesocket(hSocket); return error("Error sending to proxy"); } char pchRet1[2]; if (recv(hSocket, pchRet1, 2, 0) != 2) { closesocket(hSocket); return error("Error reading proxy response"); } if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) { closesocket(hSocket); return error("Proxy failed to initialize"); } string strSocks5("\5\1"); strSocks5 += '\000'; strSocks5 += '\003'; strSocks5 += static_cast<char>(std::min((int)strDest.size(), 255)); strSocks5 += strDest; strSocks5 += static_cast<char>((port >> 8) & 0xFF); strSocks5 += static_cast<char>((port >> 0) & 0xFF); ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); if (ret != (ssize_t)strSocks5.size()) { closesocket(hSocket); return error("Error sending to proxy"); } char pchRet2[4]; if (recv(hSocket, pchRet2, 4, 0) != 4) { closesocket(hSocket); return error("Error reading proxy response"); } if (pchRet2[0] != 0x05) { closesocket(hSocket); return error("Proxy failed to accept request"); } if (pchRet2[1] != 0x00) { closesocket(hSocket); switch (pchRet2[1]) { case 0x01: return error("Proxy error: general failure"); case 0x02: return error("Proxy error: connection not allowed"); case 0x03: return error("Proxy error: network unreachable"); case 0x04: return error("Proxy error: host unreachable"); case 0x05: return error("Proxy error: connection refused"); case 0x06: return error("Proxy error: TTL expired"); case 0x07: return error("Proxy error: protocol error"); case 0x08: return error("Proxy error: address type not supported"); default: return error("Proxy error: unknown"); } } if (pchRet2[2] != 0x00) { closesocket(hSocket); return error("Error: malformed proxy response"); } char pchRet3[256]; switch (pchRet2[3]) { case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break; case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break; case 0x03: { ret = recv(hSocket, pchRet3, 1, 0) != 1; if (ret) 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"); } if (ret) { closesocket(hSocket); return error("Error reading from proxy"); } if (recv(hSocket, pchRet3, 2, 0) != 2) { closesocket(hSocket); return error("Error reading from proxy"); } printf("SOCKS5 connected %s\n", strDest.c_str()); return true; } bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; struct sockaddr_storage sockaddr; int nFamily = 0; size_t nSockAddrLen = 0; if (addrConnect.IsIPv4()) { // Use IPv4 stack to connect to IPv4 addresses struct sockaddr_in sockaddr4; if (!addrConnect.GetSockAddr(&sockaddr4)) return false; memcpy(&sockaddr, &sockaddr4, sizeof(sockaddr4)); nSockAddrLen = sizeof(sockaddr4); nFamily = AF_INET; } #ifdef USE_IPV6 else if (addrConnect.IsIPv6()) { struct sockaddr_in6 sockaddr6; if (!addrConnect.GetSockAddr6(&sockaddr6)) return false; memcpy(&sockaddr, &sockaddr6, sizeof(sockaddr6)); nSockAddrLen = sizeof(sockaddr6); nFamily = AF_INET6; } #endif else { printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str()); return false; } SOCKET hSocket = socket(nFamily, SOCK_STREAM, IPPROTO_TCP); if (hSocket == INVALID_SOCKET) return false; #ifdef SO_NOSIGPIPE int set = 1; setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); #endif #ifdef WIN32 u_long fNonblock = 1; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else int fFlags = fcntl(hSocket, F_GETFL, 0); if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) #endif { closesocket(hSocket); return false; } if (connect(hSocket, (struct sockaddr*)&sockaddr, nSockAddrLen) == SOCKET_ERROR) { // WSAEINVAL is here because some legacy version of winsock uses it if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) { struct timeval timeout; timeout.tv_sec = nTimeout / 1000; timeout.tv_usec = (nTimeout % 1000) * 1000; fd_set fdset; FD_ZERO(&fdset); FD_SET(hSocket, &fdset); int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout); if (nRet == 0) { printf("connection timeout\n"); closesocket(hSocket); return false; } if (nRet == SOCKET_ERROR) { printf("select() for connection failed: %i\n",WSAGetLastError()); closesocket(hSocket); return false; } socklen_t nRetSize = sizeof(nRet); #ifdef WIN32 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) #else if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) #endif { printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); closesocket(hSocket); return false; } if (nRet != 0) { printf("connect() failed after select(): %s\n",strerror(nRet)); closesocket(hSocket); return false; } } #ifdef WIN32 else if (WSAGetLastError() != WSAEISCONN) #else else #endif { printf("connect() failed: %i\n",WSAGetLastError()); closesocket(hSocket); return false; } } // this isn't even strictly necessary // CNode::ConnectNode immediately turns the socket back to non-blocking // but we'll turn it back to blocking just in case #ifdef WIN32 fNonblock = 0; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else fFlags = fcntl(hSocket, F_GETFL, 0); if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) #endif { closesocket(hSocket); return false; } hSocketRet = hSocket; return true; } bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) { SOCKET hSocket = INVALID_SOCKET; bool fProxy = (fUseProxy && addrDest.IsRoutable()); if (!ConnectSocketDirectly(fProxy ? addrProxy : addrDest, hSocket, nTimeout)) return false; if (fProxy) { switch(nSocksVersion) { case 4: if (!Socks4(addrDest, hSocket)) return false; break; case 5: default: if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) return false; break; } } hSocketRet = hSocket; return true; } bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout) { string strDest(pszDest); int port = portDefault; size_t colon = strDest.find_last_of(':'); char *endp = NULL; int n = strtol(pszDest + colon + 1, &endp, 10); if (endp && *endp == 0 && n >= 0) { strDest = strDest.substr(0, colon); if (n > 0 && n < 0x10000) port = n; } if (strDest[0] == '[' && strDest[strDest.size()-1] == ']') strDest = strDest.substr(1, strDest.size()-2); SOCKET hSocket = INVALID_SOCKET; CService addrResolved(CNetAddr(strDest, fNameLookup && !fProxyNameLookup), port); if (addrResolved.IsValid()) { addr = addrResolved; return ConnectSocket(addr, hSocketRet, nTimeout); } addr = CService("0.0.0.0:0"); if (!fNameLookup) return false; if (!ConnectSocketDirectly(addrProxy, hSocket, nTimeout)) return false; switch(nSocksVersion) { case 4: return false; case 5: default: if (!Socks5(strDest, port, hSocket)) return false; break; } hSocketRet = hSocket; return true; } void CNetAddr::Init() { memset(ip, 0, 16); } void CNetAddr::SetIP(const CNetAddr& ipIn) { memcpy(ip, ipIn.ip, sizeof(ip)); } CNetAddr::CNetAddr() { Init(); } CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) { memcpy(ip, pchIPv4, 12); memcpy(ip+12, &ipv4Addr, 4); } #ifdef USE_IPV6 CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) { memcpy(ip, &ipv6Addr, 16); } #endif CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) { Init(); std::vector<CNetAddr> vIP; if (LookupHost(pszIp, vIP, 1, fAllowLookup)) *this = vIP[0]; } CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) { Init(); std::vector<CNetAddr> vIP; if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) *this = vIP[0]; } 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()); } 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::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 unsigned char 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 unsigned char 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 unsigned char 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::IsOnionCat() const { static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); } bool CNetAddr::IsGarliCat() const { static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5}; 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 unsigned char 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 { // Clean up 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) unsigned char 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() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal()); } std::string CNetAddr::ToStringIP() const { if (IsIPv4()) return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); else 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; } #ifdef USE_IPV6 bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const { memcpy(pipv6Addr, ip, 16); return true; } #endif // get canonical identifier of an address' group // no two connections will be attempted to addresses with the same group std::vector<unsigned char> CNetAddr::GetGroup() const { std::vector<unsigned char> vchRet; int nClass = 0; // 0=IPv6, 1=IPv4, 254=local, 255=unroutable int nStartByte = 0; int nBits = 16; // all local addresses belong to the same group if (IsLocal()) { nClass = 254; nBits = 0; } // all unroutable addresses belong to the same group if (!IsRoutable()) { nClass = 255; 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 = 1; nStartByte = 12; } // for 6to4 tunneled addresses, use the encapsulated IPv4 address else if (IsRFC3964()) { nClass = 1; nStartByte = 2; } // for Teredo-tunneled IPv6 addresses, use the encapsulated IPv4 address else if (IsRFC4380()) { vchRet.push_back(1); vchRet.push_back(GetByte(3) ^ 0xFF); vchRet.push_back(GetByte(2) ^ 0xFF); return vchRet; } // for he.net, use /36 groups else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) nBits = 36; // for the rest of the IPv6 network, use /32 groups else 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; } int64 CNetAddr::GetHash() const { uint256 hash = Hash(&ip[0], &ip[16]); int64 nRet; memcpy(&nRet, &hash, sizeof(nRet)); return nRet; } void CNetAddr::print() const { printf("CNetAddr(%s)\n", ToString().c_str()); } // for IPv6 partners: for unknown/Teredo partners: for IPv4 partners: // 0 - unroutable // 0 - unroutable // 0 - unroutable // 1 - teredo // 1 - teredo // 1 - ipv4 // 2 - tunneled ipv6 // 2 - tunneled ipv6 // 3 - ipv4 // 3 - ipv6 // 4 - ipv6 // 4 - ipv4 int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { if (!IsValid() || !IsRoutable()) return 0; if (paddrPartner && paddrPartner->IsIPv4()) return IsIPv4() ? 1 : 0; if (IsRFC4380()) return 1; if (IsRFC3964() || IsRFC6052()) return 2; bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable(); if (fRealIPv6) return IsIPv4() ? 3 : 4; else return IsIPv4() ? 4 : 3; } void CService::Init() { port = 0; } CService::CService() { Init(); } CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn) { } CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) { } #ifdef USE_IPV6 CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) { } #endif CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) { assert(addr.sin_family == AF_INET); } #ifdef USE_IPV6 CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) { assert(addr.sin6_family == AF_INET6); } #endif CService::CService(const char *pszIpPort, bool fAllowLookup) { Init(); CService ip; if (Lookup(pszIpPort, ip, 0, fAllowLookup)) *this = ip; } CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) { Init(); CService ip; if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) *this = ip; } CService::CService(const std::string &strIpPort, bool fAllowLookup) { Init(); CService ip; if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) *this = ip; } CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup) { Init(); CService ip; if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) *this = ip; } unsigned short CService::GetPort() const { return port; } bool operator==(const CService& a, const CService& b) { return (CNetAddr)a == (CNetAddr)b && a.port == b.port; } bool operator!=(const CService& a, const CService& b) { return (CNetAddr)a != (CNetAddr)b || a.port != b.port; } bool operator<(const CService& a, const CService& b) { return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); } bool CService::GetSockAddr(struct sockaddr_in* paddr) const { if (!IsIPv4()) return false; memset(paddr, 0, sizeof(struct sockaddr_in)); if (!GetInAddr(&paddr->sin_addr)) return false; paddr->sin_family = AF_INET; paddr->sin_port = htons(port); return true; } #ifdef USE_IPV6 bool CService::GetSockAddr6(struct sockaddr_in6* paddr) const { memset(paddr, 0, sizeof(struct sockaddr_in6)); if (!GetIn6Addr(&paddr->sin6_addr)) return false; paddr->sin6_family = AF_INET6; paddr->sin6_port = htons(port); return true; } #endif std::vector<unsigned char> CService::GetKey() const { std::vector<unsigned char> vKey; vKey.resize(18); memcpy(&vKey[0], ip, 16); vKey[16] = port / 0x100; vKey[17] = port & 0x0FF; return vKey; } std::string CService::ToStringPort() const { return strprintf("%i", port); } std::string CService::ToStringIPPort() const { if (IsIPv4()) { return ToStringIP() + ":" + ToStringPort(); } else { return "[" + ToStringIP() + "]:" + ToStringPort(); } } std::string CService::ToString() const { return ToStringIPPort(); } void CService::print() const { printf("CService(%s)\n", ToString().c_str()); } void CService::SetPort(unsigned short portIn) { port = portIn; }