Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/netbase.cpp
Show All 10 Lines | |||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#endif | #endif | ||||
#include <boost/algorithm/string/case_conv.hpp> // for to_lower() | #include <boost/algorithm/string/case_conv.hpp> // for to_lower() | ||||
#define printf my_printf | #define printf my_printf | ||||
// Settings | // Settings | ||||
typedef std::pair<CSeederService, int> proxyType; | typedef std::pair<CService, int> proxyType; | ||||
static proxyType proxyInfo[NET_MAX]; | static proxyType proxyInfo[NET_MAX]; | ||||
static proxyType nameproxyInfo; | static proxyType nameproxyInfo; | ||||
int nConnectTimeout = 5000; | |||||
bool fNameLookup = false; | |||||
static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; | static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; | ||||
static void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { | static bool Socks4(const CService &addrDest, SOCKET &hSocket) { | ||||
size_t colon = in.find_last_of(':'); | |||||
// if a : is found, and it either follows a [...], or no other : is in the | |||||
// string, treat it as port separator | |||||
bool fHaveColon = colon != in.npos; | |||||
// if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is | |||||
// safe | |||||
bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); | |||||
bool fMultiColon = | |||||
fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); | |||||
if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { | |||||
char *endp = nullptr; | |||||
int n = strtol(in.c_str() + colon + 1, &endp, 10); | |||||
if (endp && *endp == 0 && n >= 0) { | |||||
in = in.substr(0, colon); | |||||
if (n > 0 && n < 0x10000) portOut = n; | |||||
} | |||||
} | |||||
if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') | |||||
hostOut = in.substr(1, in.size() - 2); | |||||
else | |||||
hostOut = in; | |||||
} | |||||
static bool LookupIntern(const char *pszName, std::vector<CNetAddr> &vIP, | |||||
unsigned int nMaxSolutions, bool fAllowLookup) { | |||||
vIP.clear(); | |||||
{ | |||||
CNetAddr addr; | |||||
if (addr.SetSpecial(std::string(pszName))) { | |||||
vIP.push_back(addr); | |||||
return true; | |||||
} | |||||
} | |||||
struct addrinfo aiHint; | |||||
memset(&aiHint, 0, sizeof(struct addrinfo)); | |||||
aiHint.ai_socktype = SOCK_STREAM; | |||||
aiHint.ai_protocol = IPPROTO_TCP; | |||||
#ifdef WIN32 | |||||
aiHint.ai_family = AF_UNSPEC; | |||||
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; | |||||
#else | |||||
aiHint.ai_family = AF_UNSPEC; | |||||
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; | |||||
#endif | |||||
struct addrinfo *aiRes = nullptr; | |||||
int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes); | |||||
if (nErr) return false; | |||||
struct addrinfo *aiTrav = aiRes; | |||||
while (aiTrav != nullptr && | |||||
(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)); | |||||
} | |||||
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)); | |||||
} | |||||
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); | |||||
} | |||||
static bool Lookup(const char *pszName, std::vector<CSeederService> &vAddr, | |||||
int portDefault, bool fAllowLookup, | |||||
unsigned int nMaxSolutions) { | |||||
if (pszName[0] == 0) return false; | |||||
int port = portDefault; | |||||
std::string hostname = ""; | |||||
SplitHostPort(std::string(pszName), port, hostname); | |||||
std::vector<CNetAddr> vIP; | |||||
bool fRet = | |||||
LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); | |||||
if (!fRet) return false; | |||||
vAddr.resize(vIP.size()); | |||||
for (unsigned int i = 0; i < vIP.size(); i++) | |||||
vAddr[i] = CSeederService(vIP[i], port); | |||||
return true; | |||||
} | |||||
static bool Lookup(const char *pszName, CSeederService &addr, int portDefault, | |||||
bool fAllowLookup) { | |||||
std::vector<CSeederService> vService; | |||||
bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); | |||||
if (!fRet) return false; | |||||
addr = vService[0]; | |||||
return true; | |||||
} | |||||
static bool Socks4(const CSeederService &addrDest, SOCKET &hSocket) { | |||||
printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); | printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); | ||||
if (!addrDest.IsIPv4()) { | if (!addrDest.IsIPv4()) { | ||||
closesocket(hSocket); | closesocket(hSocket); | ||||
return error("Proxy destination is not IPv4"); | return error("Proxy destination is not IPv4"); | ||||
} | } | ||||
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; | char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; | ||||
struct sockaddr_in addr; | struct sockaddr_in addr; | ||||
socklen_t len = sizeof(addr); | socklen_t len = sizeof(addr); | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | static bool Socks5(std::string strDest, int port, SOCKET &hSocket) { | ||||
if (recv(hSocket, pchRet3, 2, 0) != 2) { | if (recv(hSocket, pchRet3, 2, 0) != 2) { | ||||
closesocket(hSocket); | closesocket(hSocket); | ||||
return error("Error reading from proxy"); | return error("Error reading from proxy"); | ||||
} | } | ||||
printf("SOCKS5 connected %s\n", strDest.c_str()); | printf("SOCKS5 connected %s\n", strDest.c_str()); | ||||
return true; | return true; | ||||
} | } | ||||
static bool ConnectSocketDirectly(const CSeederService &addrConnect, | static bool ConnectSocketDirectly(const CService &addrConnect, | ||||
SOCKET &hSocketRet, int nTimeout) { | SOCKET &hSocketRet, int nTimeout) { | ||||
hSocketRet = INVALID_SOCKET; | hSocketRet = INVALID_SOCKET; | ||||
struct sockaddr_storage sockaddr; | struct sockaddr_storage sockaddr; | ||||
socklen_t len = sizeof(sockaddr); | socklen_t len = sizeof(sockaddr); | ||||
if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) { | if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) { | ||||
printf("Cannot connect to %s: unsupported network\n", | printf("Cannot connect to %s: unsupported network\n", | ||||
addrConnect.ToString().c_str()); | addrConnect.ToString().c_str()); | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | #endif | ||||
closesocket(hSocket); | closesocket(hSocket); | ||||
return false; | return false; | ||||
} | } | ||||
hSocketRet = hSocket; | hSocketRet = hSocket; | ||||
return true; | return true; | ||||
} | } | ||||
bool SetProxy(enum Network net, CSeederService addrProxy, int nSocksVersion) { | bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { | ||||
assert(net >= 0 && net < NET_MAX); | assert(net >= 0 && net < NET_MAX); | ||||
if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) | if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) | ||||
return false; | return false; | ||||
if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; | if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; | ||||
proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); | proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); | ||||
return true; | return true; | ||||
} | } | ||||
bool ConnectSocket(const CSeederService &addrDest, SOCKET &hSocketRet, | bool ConnectSocket(const CService &addrDest, SOCKET &hSocketRet, int nTimeout) { | ||||
int nTimeout) { | |||||
const proxyType &proxy = proxyInfo[addrDest.GetNetwork()]; | const proxyType &proxy = proxyInfo[addrDest.GetNetwork()]; | ||||
// no proxy needed | // no proxy needed | ||||
if (!proxy.second) | if (!proxy.second) | ||||
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); | return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); | ||||
SOCKET hSocket = INVALID_SOCKET; | SOCKET hSocket = INVALID_SOCKET; | ||||
Show All 11 Lines | switch (proxy.second) { | ||||
break; | break; | ||||
default: | default: | ||||
return false; | return false; | ||||
} | } | ||||
hSocketRet = hSocket; | hSocketRet = hSocket; | ||||
return true; | return true; | ||||
} | } | ||||
void CSeederService::Init() { | |||||
port = 0; | |||||
} | |||||
CSeederService::CSeederService() { | |||||
Init(); | |||||
} | |||||
CSeederService::CSeederService(const CNetAddr &cip, unsigned short portIn) | |||||
: CNetAddr(cip), port(portIn) {} | |||||
CSeederService::CSeederService(const struct in_addr &ipv4Addr, | |||||
unsigned short portIn) | |||||
: CNetAddr(ipv4Addr), port(portIn) {} | |||||
CSeederService::CSeederService(const struct in6_addr &ipv6Addr, | |||||
unsigned short portIn) | |||||
: CNetAddr(ipv6Addr), port(portIn) {} | |||||
CSeederService::CSeederService(const struct sockaddr_in &addr) | |||||
: CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) { | |||||
assert(addr.sin_family == AF_INET); | |||||
} | |||||
CSeederService::CSeederService(const struct sockaddr_in6 &addr) | |||||
: CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) { | |||||
assert(addr.sin6_family == AF_INET6); | |||||
} | |||||
bool CSeederService::SetSockAddr(const struct sockaddr *paddr) { | |||||
switch (paddr->sa_family) { | |||||
case AF_INET: | |||||
*this = CSeederService(*(const struct sockaddr_in *)paddr); | |||||
return true; | |||||
case AF_INET6: | |||||
*this = CSeederService(*(const struct sockaddr_in6 *)paddr); | |||||
return true; | |||||
default: | |||||
return false; | |||||
} | |||||
} | |||||
CSeederService::CSeederService(const char *pszIpPort, bool fAllowLookup) { | |||||
Init(); | |||||
CSeederService ip; | |||||
if (Lookup(pszIpPort, ip, 0, fAllowLookup)) *this = ip; | |||||
} | |||||
CSeederService::CSeederService(const char *pszIpPort, int portDefault, | |||||
bool fAllowLookup) { | |||||
Init(); | |||||
CSeederService ip; | |||||
if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) *this = ip; | |||||
} | |||||
CSeederService::CSeederService(const std::string &strIpPort, | |||||
bool fAllowLookup) { | |||||
Init(); | |||||
CSeederService ip; | |||||
if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) *this = ip; | |||||
} | |||||
CSeederService::CSeederService(const std::string &strIpPort, int portDefault, | |||||
bool fAllowLookup) { | |||||
Init(); | |||||
CSeederService ip; | |||||
if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) *this = ip; | |||||
} | |||||
unsigned short CSeederService::GetPort() const { | |||||
return port; | |||||
} | |||||
bool operator==(const CSeederService &a, const CSeederService &b) { | |||||
return (CNetAddr)a == (CNetAddr)b && a.port == b.port; | |||||
} | |||||
bool operator!=(const CSeederService &a, const CSeederService &b) { | |||||
return (CNetAddr)a != (CNetAddr)b || a.port != b.port; | |||||
} | |||||
bool operator<(const CSeederService &a, const CSeederService &b) { | |||||
return (CNetAddr)a < (CNetAddr)b || | |||||
((CNetAddr)a == (CNetAddr)b && a.port < b.port); | |||||
} | |||||
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); | |||||
struct sockaddr_in *paddrin = (struct sockaddr_in *)paddr; | |||||
memset(paddrin, 0, *addrlen); | |||||
if (!GetInAddr(&paddrin->sin_addr)) return false; | |||||
paddrin->sin_family = AF_INET; | |||||
paddrin->sin_port = htons(port); | |||||
return true; | |||||
} | |||||
if (IsIPv6()) { | |||||
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) return false; | |||||
*addrlen = sizeof(struct sockaddr_in6); | |||||
struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6 *)paddr; | |||||
memset(paddrin6, 0, *addrlen); | |||||
if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; | |||||
paddrin6->sin6_family = AF_INET6; | |||||
paddrin6->sin6_port = htons(port); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
std::vector<uint8_t> CSeederService::GetKey() const { | |||||
std::vector<uint8_t> vKey; | |||||
vKey.resize(18); | |||||
memcpy(&vKey[0], ip, 16); | |||||
vKey[16] = port / 0x100; | |||||
vKey[17] = port & 0x0FF; | |||||
return vKey; | |||||
} | |||||
std::string CSeederService::ToStringPort() const { | |||||
return strprintf("%u", port); | |||||
} | |||||
std::string CSeederService::ToStringIPPort() const { | |||||
if (IsIPv4() || IsTor()) { | |||||
return ToStringIP() + ":" + ToStringPort(); | |||||
} else { | |||||
return "[" + ToStringIP() + "]:" + ToStringPort(); | |||||
} | |||||
} | |||||
std::string CSeederService::ToString() const { | |||||
return ToStringIPPort(); | |||||
} | |||||
void CSeederService::print() const { | |||||
printf("CSeederService(%s)\n", ToString().c_str()); | |||||
} | |||||
void CSeederService::SetPort(unsigned short portIn) { | |||||
port = portIn; | |||||
} |