Changeset View
Changeset View
Standalone View
Standalone View
src/netbase.cpp
Show All 32 Lines | |||||
// Need ample time for negotiation for very slow proxies such as Tor | // Need ample time for negotiation for very slow proxies such as Tor | ||||
// (milliseconds) | // (milliseconds) | ||||
static const int SOCKS5_RECV_TIMEOUT = 20 * 1000; | static const int SOCKS5_RECV_TIMEOUT = 20 * 1000; | ||||
static std::atomic<bool> interruptSocks5Recv(false); | static std::atomic<bool> interruptSocks5Recv(false); | ||||
enum Network ParseNetwork(std::string net) { | enum Network ParseNetwork(std::string net) { | ||||
boost::to_lower(net); | boost::to_lower(net); | ||||
if (net == "ipv4") return NET_IPV4; | if (net == "ipv4") { | ||||
if (net == "ipv6") return NET_IPV6; | return NET_IPV4; | ||||
if (net == "tor" || net == "onion") return NET_TOR; | } | ||||
if (net == "ipv6") { | |||||
return NET_IPV6; | |||||
} | |||||
if (net == "tor" || net == "onion") { | |||||
return NET_TOR; | |||||
} | |||||
return NET_UNROUTABLE; | return NET_UNROUTABLE; | ||||
} | } | ||||
std::string GetNetworkName(enum Network net) { | std::string GetNetworkName(enum Network net) { | ||||
switch (net) { | switch (net) { | ||||
case NET_IPV4: | case NET_IPV4: | ||||
return "ipv4"; | return "ipv4"; | ||||
case NET_IPV6: | case NET_IPV6: | ||||
Show All 25 Lines | static bool LookupIntern(const char *pszName, std::vector<CNetAddr> &vIP, | ||||
aiHint.ai_family = AF_UNSPEC; | aiHint.ai_family = AF_UNSPEC; | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; | aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; | ||||
#else | #else | ||||
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; | aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; | ||||
#endif | #endif | ||||
struct addrinfo *aiRes = nullptr; | struct addrinfo *aiRes = nullptr; | ||||
int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes); | int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes); | ||||
if (nErr) return false; | if (nErr) { | ||||
return false; | |||||
} | |||||
struct addrinfo *aiTrav = aiRes; | struct addrinfo *aiTrav = aiRes; | ||||
while (aiTrav != nullptr && | while (aiTrav != nullptr && | ||||
(nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { | (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { | ||||
CNetAddr resolved; | CNetAddr resolved; | ||||
if (aiTrav->ai_family == AF_INET) { | if (aiTrav->ai_family == AF_INET) { | ||||
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); | assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); | ||||
resolved = | resolved = | ||||
Show All 33 Lines | bool LookupHost(const char *pszName, std::vector<CNetAddr> &vIP, | ||||
} | } | ||||
return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup); | return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup); | ||||
} | } | ||||
bool LookupHost(const char *pszName, CNetAddr &addr, bool fAllowLookup) { | bool LookupHost(const char *pszName, CNetAddr &addr, bool fAllowLookup) { | ||||
std::vector<CNetAddr> vIP; | std::vector<CNetAddr> vIP; | ||||
LookupHost(pszName, vIP, 1, fAllowLookup); | LookupHost(pszName, vIP, 1, fAllowLookup); | ||||
if (vIP.empty()) return false; | if (vIP.empty()) { | ||||
return false; | |||||
} | |||||
addr = vIP.front(); | addr = vIP.front(); | ||||
return true; | return true; | ||||
} | } | ||||
bool Lookup(const char *pszName, std::vector<CService> &vAddr, int portDefault, | bool Lookup(const char *pszName, std::vector<CService> &vAddr, int portDefault, | ||||
bool fAllowLookup, unsigned int nMaxSolutions) { | bool fAllowLookup, unsigned int nMaxSolutions) { | ||||
if (pszName[0] == 0) return false; | if (pszName[0] == 0) { | ||||
return false; | |||||
} | |||||
int port = portDefault; | int port = portDefault; | ||||
std::string hostname = ""; | std::string hostname = ""; | ||||
SplitHostPort(std::string(pszName), port, hostname); | SplitHostPort(std::string(pszName), port, hostname); | ||||
std::vector<CNetAddr> vIP; | std::vector<CNetAddr> vIP; | ||||
bool fRet = | bool fRet = | ||||
LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); | LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); | ||||
if (!fRet) return false; | if (!fRet) { | ||||
return false; | |||||
} | |||||
vAddr.resize(vIP.size()); | vAddr.resize(vIP.size()); | ||||
for (unsigned int i = 0; i < vIP.size(); i++) | for (unsigned int i = 0; i < vIP.size(); i++) { | ||||
vAddr[i] = CService(vIP[i], port); | vAddr[i] = CService(vIP[i], port); | ||||
} | |||||
return true; | return true; | ||||
} | } | ||||
bool Lookup(const char *pszName, CService &addr, int portDefault, | bool Lookup(const char *pszName, CService &addr, int portDefault, | ||||
bool fAllowLookup) { | bool fAllowLookup) { | ||||
std::vector<CService> vService; | std::vector<CService> vService; | ||||
bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); | bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); | ||||
if (!fRet) return false; | if (!fRet) { | ||||
return false; | |||||
} | |||||
addr = vService[0]; | addr = vService[0]; | ||||
return true; | return true; | ||||
} | } | ||||
CService LookupNumeric(const char *pszName, int portDefault) { | CService LookupNumeric(const char *pszName, int portDefault) { | ||||
CService addr; | CService addr; | ||||
// "1.2:345" will fail to resolve the ip, but will still set the port. | // "1.2:345" will fail to resolve the ip, but will still set the port. | ||||
// If the ip fails to resolve, re-init the result. | // If the ip fails to resolve, re-init the result. | ||||
if (!Lookup(pszName, addr, portDefault, false)) addr = CService(); | if (!Lookup(pszName, addr, portDefault, false)) { | ||||
addr = CService(); | |||||
} | |||||
return addr; | return addr; | ||||
} | } | ||||
struct timeval MillisToTimeval(int64_t nTimeout) { | struct timeval MillisToTimeval(int64_t nTimeout) { | ||||
struct timeval timeout; | struct timeval timeout; | ||||
timeout.tv_sec = nTimeout / 1000; | timeout.tv_sec = nTimeout / 1000; | ||||
timeout.tv_usec = (nTimeout % 1000) * 1000; | timeout.tv_usec = (nTimeout % 1000) * 1000; | ||||
return timeout; | return timeout; | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | static bool Socks5(const std::string &strDest, int port, | ||||
if (pchRet1[0] != SOCKSVersion::SOCKS5) { | if (pchRet1[0] != SOCKSVersion::SOCKS5) { | ||||
return error("Proxy failed to initialize"); | return error("Proxy failed to initialize"); | ||||
} | } | ||||
if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) { | if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) { | ||||
// Perform username/password authentication (as described in RFC1929) | // Perform username/password authentication (as described in RFC1929) | ||||
std::vector<uint8_t> vAuth; | std::vector<uint8_t> vAuth; | ||||
// Current (and only) version of user/pass subnegotiation | // Current (and only) version of user/pass subnegotiation | ||||
vAuth.push_back(0x01); | vAuth.push_back(0x01); | ||||
if (auth->username.size() > 255 || auth->password.size() > 255) | if (auth->username.size() > 255 || auth->password.size() > 255) { | ||||
return error("Proxy username or password too long"); | return error("Proxy username or password too long"); | ||||
} | |||||
vAuth.push_back(auth->username.size()); | vAuth.push_back(auth->username.size()); | ||||
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); | vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); | ||||
vAuth.push_back(auth->password.size()); | vAuth.push_back(auth->password.size()); | ||||
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); | vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); | ||||
ret = send(hSocket, (const char *)vAuth.data(), vAuth.size(), | ret = send(hSocket, (const char *)vAuth.data(), vAuth.size(), | ||||
MSG_NOSIGNAL); | MSG_NOSIGNAL); | ||||
if (ret != (ssize_t)vAuth.size()) { | if (ret != (ssize_t)vAuth.size()) { | ||||
return error("Error sending authentication to proxy"); | return error("Error sending authentication to proxy"); | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | #endif | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool SetProxy(enum Network net, const proxyType &addrProxy) { | bool SetProxy(enum Network net, const proxyType &addrProxy) { | ||||
assert(net >= 0 && net < NET_MAX); | assert(net >= 0 && net < NET_MAX); | ||||
if (!addrProxy.IsValid()) return false; | if (!addrProxy.IsValid()) { | ||||
return false; | |||||
} | |||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
proxyInfo[net] = addrProxy; | proxyInfo[net] = addrProxy; | ||||
return true; | return true; | ||||
} | } | ||||
bool GetProxy(enum Network net, proxyType &proxyInfoOut) { | bool GetProxy(enum Network net, proxyType &proxyInfoOut) { | ||||
assert(net >= 0 && net < NET_MAX); | assert(net >= 0 && net < NET_MAX); | ||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
if (!proxyInfo[net].IsValid()) return false; | if (!proxyInfo[net].IsValid()) { | ||||
return false; | |||||
} | |||||
proxyInfoOut = proxyInfo[net]; | proxyInfoOut = proxyInfo[net]; | ||||
return true; | return true; | ||||
} | } | ||||
bool SetNameProxy(const proxyType &addrProxy) { | bool SetNameProxy(const proxyType &addrProxy) { | ||||
if (!addrProxy.IsValid()) return false; | if (!addrProxy.IsValid()) { | ||||
return false; | |||||
} | |||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
nameProxy = addrProxy; | nameProxy = addrProxy; | ||||
return true; | return true; | ||||
} | } | ||||
bool GetNameProxy(proxyType &nameProxyOut) { | bool GetNameProxy(proxyType &nameProxyOut) { | ||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
if (!nameProxy.IsValid()) return false; | if (!nameProxy.IsValid()) { | ||||
return false; | |||||
} | |||||
nameProxyOut = nameProxy; | nameProxyOut = nameProxy; | ||||
return true; | return true; | ||||
} | } | ||||
bool HaveNameProxy() { | bool HaveNameProxy() { | ||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
return nameProxy.IsValid(); | return nameProxy.IsValid(); | ||||
} | } | ||||
bool IsProxy(const CNetAddr &addr) { | bool IsProxy(const CNetAddr &addr) { | ||||
LOCK(cs_proxyInfos); | LOCK(cs_proxyInfos); | ||||
for (int i = 0; i < NET_MAX; i++) { | for (int i = 0; i < NET_MAX; i++) { | ||||
if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) { | if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest, | bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest, | ||||
int port, const SOCKET &hSocket, int nTimeout, | int port, const SOCKET &hSocket, int nTimeout, | ||||
bool *outProxyConnectionFailed) { | bool *outProxyConnectionFailed) { | ||||
// first connect to proxy server | // first connect to proxy server | ||||
if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) { | if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) { | ||||
if (outProxyConnectionFailed) *outProxyConnectionFailed = true; | if (outProxyConnectionFailed) { | ||||
*outProxyConnectionFailed = true; | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
// do socks negotiation | // do socks negotiation | ||||
if (proxy.randomize_credentials) { | if (proxy.randomize_credentials) { | ||||
ProxyCredentials random_auth; | ProxyCredentials random_auth; | ||||
static std::atomic_int counter(0); | static std::atomic_int counter(0); | ||||
random_auth.username = random_auth.password = | random_auth.username = random_auth.password = | ||||
strprintf("%i", counter++); | strprintf("%i", counter++); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | std::string NetworkErrorString(int err) { | ||||
buf[0] = 0; | buf[0] = 0; | ||||
/* Too bad there are two incompatible implementations of the | /* Too bad there are two incompatible implementations of the | ||||
* thread-safe strerror. */ | * thread-safe strerror. */ | ||||
#ifdef STRERROR_R_CHAR_P | #ifdef STRERROR_R_CHAR_P | ||||
/* GNU variant can return a pointer outside the passed buffer */ | /* GNU variant can return a pointer outside the passed buffer */ | ||||
s = strerror_r(err, buf, sizeof(buf)); | s = strerror_r(err, buf, sizeof(buf)); | ||||
#else | #else | ||||
/* POSIX variant always returns message in buffer */ | /* POSIX variant always returns message in buffer */ | ||||
if (strerror_r(err, buf, sizeof(buf))) buf[0] = 0; | if (strerror_r(err, buf, sizeof(buf))) { | ||||
buf[0] = 0; | |||||
} | |||||
#endif | #endif | ||||
return strprintf("%s (%d)", s, err); | return strprintf("%s (%d)", s, err); | ||||
} | } | ||||
#endif | #endif | ||||
bool CloseSocket(SOCKET &hSocket) { | bool CloseSocket(SOCKET &hSocket) { | ||||
if (hSocket == INVALID_SOCKET) return false; | if (hSocket == INVALID_SOCKET) { | ||||
return false; | |||||
} | |||||
#ifdef WIN32 | #ifdef WIN32 | ||||
int ret = closesocket(hSocket); | int ret = closesocket(hSocket); | ||||
#else | #else | ||||
int ret = close(hSocket); | int ret = close(hSocket); | ||||
#endif | #endif | ||||
hSocket = INVALID_SOCKET; | hSocket = INVALID_SOCKET; | ||||
return ret != SOCKET_ERROR; | return ret != SOCKET_ERROR; | ||||
} | } | ||||
Show All 37 Lines |