LCOV - code coverage report
Current view: top level - src - netbase.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 282 368 76.6 %
Date: 2025-02-23 09:33:43 Functions: 26 28 92.9 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2015 The Bitcoin developers
       3             : // Copyright (c) 2017-2022 The PIVX Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include "netbase.h"
       8             : 
       9             : #include "sync.h"
      10             : #include "random.h"
      11             : #include "tinyformat.h"
      12             : #include "util/string.h"
      13             : #include "util/system.h"
      14             : #include "utilstrencodings.h"
      15             : 
      16             : #include <atomic>
      17             : #include <cstdint>
      18             : #include <limits>
      19             : 
      20             : #ifndef WIN32
      21             : #include <fcntl.h>
      22             : #else
      23             : #include <codecvt>
      24             : #endif
      25             : 
      26             : #ifdef USE_POLL
      27             : #include <poll.h>
      28             : #endif
      29             : 
      30             : #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
      31             : #define MSG_NOSIGNAL 0
      32             : #endif
      33             : 
      34             : 
      35             : // Settings
      36             : static proxyType proxyInfo[NET_MAX];
      37             : static proxyType nameProxy;
      38             : static RecursiveMutex cs_proxyInfos;
      39             : int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
      40             : bool fNameLookup = false;
      41             : 
      42             : // Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
      43             : static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
      44             : static std::atomic<bool> interruptSocks5Recv(false);
      45             : 
      46          17 : enum Network ParseNetwork(std::string net)
      47             : {
      48          17 :     Downcase(net);
      49          17 :     if (net == "ipv4") return NET_IPV4;
      50          13 :     if (net == "ipv6") return NET_IPV6;
      51          18 :     if (net == "tor" || net == "onion") return NET_ONION;
      52             :     return NET_UNROUTABLE;
      53             : }
      54             : 
      55       12832 : std::string GetNetworkName(enum Network net)
      56             : {
      57       12832 :     switch (net) {
      58         314 :         case NET_UNROUTABLE: return "unroutable";
      59       10073 :         case NET_IPV4: return "ipv4";
      60        1223 :         case NET_IPV6: return "ipv6";
      61        1222 :         case NET_ONION: return "onion";
      62           0 :         case NET_I2P: return "i2p";
      63           0 :         case NET_CJDNS: return "cjdns";
      64           0 :         case NET_INTERNAL: return "internal";
      65           0 :         case NET_MAX: assert(false);
      66             :     } // no default case, so the compiler can warn about missing cases
      67             : 
      68           0 :     assert(false);
      69             : }
      70             : 
      71      604649 : void SplitHostPort(std::string in, int& portOut, std::string& hostOut)
      72             : {
      73      604649 :     size_t colon = in.find_last_of(':');
      74             :     // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
      75      604649 :     bool fHaveColon = colon != in.npos;
      76      604649 :     bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
      77      604649 :     bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos);
      78      604649 :     if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
      79        2045 :         int32_t n;
      80        4090 :         if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
      81        1957 :             in = in.substr(0, colon);
      82        1957 :             portOut = n;
      83             :         }
      84             :     }
      85      604649 :     if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']')
      86          18 :         hostOut = in.substr(1, in.size() - 2);
      87             :     else
      88      604631 :         hostOut = in;
      89      604649 : }
      90             : 
      91      623055 : bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
      92             : {
      93      623055 :     vIP.clear();
      94             : 
      95      623055 :     if (!ValidAsCString(name)) {
      96             :         return false;
      97             :     }
      98             : 
      99      623055 :     {
     100      623055 :         CNetAddr addr;
     101      623055 :         if (addr.SetSpecial(name)) {
     102           7 :             vIP.push_back(addr);
     103           7 :             return true;
     104             :         }
     105             :     }
     106             : 
     107      623048 :     struct addrinfo aiHint;
     108      623048 :     memset(&aiHint, 0, sizeof(struct addrinfo));
     109             : 
     110      623048 :     aiHint.ai_socktype = SOCK_STREAM;
     111      623048 :     aiHint.ai_protocol = IPPROTO_TCP;
     112      623048 :     aiHint.ai_family = AF_UNSPEC;
     113             : #ifdef WIN32
     114             :     aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
     115             : #else
     116      623048 :     aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
     117             : #endif
     118      623048 :     struct addrinfo* aiRes = nullptr;
     119      623048 :     int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
     120      623048 :     if (nErr)
     121             :         return false;
     122             : 
     123      622940 :     struct addrinfo* aiTrav = aiRes;
     124     1245880 :     while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) {
     125     1245880 :         CNetAddr resolved;
     126      622940 :         if (aiTrav->ai_family == AF_INET) {
     127      622105 :             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
     128      622105 :             resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
     129             :         }
     130             : 
     131      622940 :         if (aiTrav->ai_family == AF_INET6) {
     132         835 :             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
     133         835 :             struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
     134         835 :             resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
     135             :         }
     136             :         /* Never allow resolving to an internal address. Consider any such result invalid */
     137      622940 :         if (!resolved.IsInternal()) {
     138      622939 :             vIP.push_back(resolved);
     139             :         }
     140             : 
     141      622940 :         aiTrav = aiTrav->ai_next;
     142             :     }
     143             : 
     144      622940 :     freeaddrinfo(aiRes);
     145             : 
     146      622940 :     return (vIP.size() > 0);
     147             : }
     148             : 
     149       19678 : bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
     150             : {
     151       19678 :     if (!ValidAsCString(name)) {
     152             :         return false;
     153             :     }
     154       39356 :     std::string strHost = name;
     155       19678 :     if (strHost.empty())
     156             :         return false;
     157       19677 :     if (strHost.front() == '[' && strHost.back() == ']') {
     158           1 :         strHost = strHost.substr(1, strHost.size() - 2);
     159             :     }
     160             : 
     161       19677 :     return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup);
     162             : }
     163             : 
     164       19490 : bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
     165             : {
     166       19490 :     if (!ValidAsCString(name)) {
     167             :         return false;
     168             :     }
     169       38974 :     std::vector<CNetAddr> vIP;
     170       19487 :     LookupHost(name, vIP, 1, fAllowLookup);
     171       19487 :     if (vIP.empty())
     172             :         return false;
     173       19389 :     addr = vIP.front();
     174       19389 :     return true;
     175             : }
     176             : 
     177      603378 : bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
     178             : {
     179      603378 :     if (name.empty() || !ValidAsCString(name)) {
     180             :         return false;
     181             :     }
     182      603378 :     int port = portDefault;
     183     1206760 :     std::string hostname;
     184     1206760 :     SplitHostPort(name, port, hostname);
     185             : 
     186     1206760 :     std::vector<CNetAddr> vIP;
     187      603378 :     bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
     188      603378 :     if (!fRet)
     189             :         return false;
     190      603372 :     vAddr.resize(vIP.size());
     191     1206746 :     for (unsigned int i = 0; i < vIP.size(); i++)
     192      603372 :         vAddr[i] = CService(vIP[i], port);
     193             :     return true;
     194             : }
     195             : 
     196      602685 : bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup)
     197             : {
     198      602685 :     if (!ValidAsCString(name)) {
     199             :         return false;
     200             :     }
     201     1205370 :     std::vector<CService> vService;
     202      602684 :     bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1);
     203      602684 :     if (!fRet)
     204             :         return false;
     205      602682 :     addr = vService[0];
     206      602682 :     return true;
     207             : }
     208             : 
     209      595285 : CService LookupNumeric(const std::string& name, int portDefault)
     210             : {
     211      595285 :     if (!ValidAsCString(name)) {
     212           0 :         return {};
     213             :     }
     214     1190574 :     CService addr;
     215             :     // "1.2:345" will fail to resolve the ip, but will still set the port.
     216             :     // If the ip fails to resolve, re-init the result.
     217      595285 :     if (!Lookup(name, addr, portDefault, false))
     218           2 :         addr = CService();
     219      595285 :     return addr;
     220             : }
     221             : 
     222           0 : struct timeval MillisToTimeval(int64_t nTimeout)
     223             : {
     224           0 :     struct timeval timeout;
     225           0 :     timeout.tv_sec = nTimeout / 1000;
     226           0 :     timeout.tv_usec = (nTimeout % 1000) * 1000;
     227           0 :     return timeout;
     228             : }
     229             : 
     230             : /** SOCKS version */
     231             : enum SOCKSVersion: uint8_t {
     232             :     SOCKS4 = 0x04,
     233             :     SOCKS5 = 0x05
     234             : };
     235             : 
     236             : /** Values defined for METHOD in RFC1928 */
     237             : enum SOCKS5Method: uint8_t {
     238             :     NOAUTH = 0x00,        //! No authentication required
     239             :     GSSAPI = 0x01,        //! GSSAPI
     240             :     USER_PASS = 0x02,     //! Username/password
     241             :     NO_ACCEPTABLE = 0xff, //! No acceptable methods
     242             : };
     243             : 
     244             : /** Values defined for CMD in RFC1928 */
     245             : enum SOCKS5Command: uint8_t {
     246             :     CONNECT = 0x01,
     247             :     BIND = 0x02,
     248             :     UDP_ASSOCIATE = 0x03
     249             : };
     250             : 
     251             : /** Values defined for REP in RFC1928 */
     252             : enum SOCKS5Reply: uint8_t {
     253             :     SUCCEEDED = 0x00,        //! Succeeded
     254             :     GENFAILURE = 0x01,       //! General failure
     255             :     NOTALLOWED = 0x02,       //! Connection not allowed by ruleset
     256             :     NETUNREACHABLE = 0x03,   //! Network unreachable
     257             :     HOSTUNREACHABLE = 0x04,  //! Network unreachable
     258             :     CONNREFUSED = 0x05,      //! Connection refused
     259             :     TTLEXPIRED = 0x06,       //! TTL expired
     260             :     CMDUNSUPPORTED = 0x07,   //! Command not supported
     261             :     ATYPEUNSUPPORTED = 0x08, //! Address type not supported
     262             : };
     263             : 
     264             : /** Values defined for ATYPE in RFC1928 */
     265             : enum SOCKS5Atyp: uint8_t {
     266             :     IPV4 = 0x01,
     267             :     DOMAINNAME = 0x03,
     268             :     IPV6 = 0x04,
     269             : };
     270             : 
     271             : /** Status codes that can be returned by InterruptibleRecv */
     272             : enum class IntrRecvError {
     273             :     OK,
     274             :     Timeout,
     275             :     Disconnected,
     276             :     NetworkError,
     277             :     Interrupted
     278             : };
     279             : 
     280             : /**
     281             :  * Read bytes from socket. This will either read the full number of bytes requested
     282             :  * or return False on error or timeout.
     283             :  * This function can be interrupted by calling InterruptSocks5()
     284             :  *
     285             :  * @param data Buffer to receive into
     286             :  * @param len  Length of data to receive
     287             :  * @param timeout  Timeout in milliseconds for receive operation
     288             :  *
     289             :  * @note This function requires that hSocket is in non-blocking mode.
     290             :  */
     291          64 : static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
     292             : {
     293          64 :     int64_t curTime = GetTimeMillis();
     294          64 :     int64_t endTime = curTime + timeout;
     295             :     // Maximum time to wait in one select call. It will take up until this time (in millis)
     296             :     // to break off in case of an interruption.
     297          64 :     const int64_t maxWait = 1000;
     298        2661 :     while (len > 0 && curTime < endTime) {
     299        2597 :         ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
     300        2597 :         if (ret > 0) {
     301          64 :             len -= ret;
     302          64 :             data += ret;
     303        2533 :         } else if (ret == 0) { // Unexpected disconnection
     304             :             return IntrRecvError::Disconnected;
     305             :         } else { // Other error or blocking
     306        2533 :             int nErr = WSAGetLastError();
     307        2533 :             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
     308        2533 :                 if (!IsSelectableSocket(hSocket)) {
     309           0 :                     return IntrRecvError::NetworkError;
     310             :                 }
     311        2533 :                 int timeout_ms = std::min(endTime - curTime, maxWait);
     312             : #ifdef USE_POLL
     313        2533 :                 struct pollfd pollfd = {};
     314        2533 :                 pollfd.fd = hSocket;
     315        2533 :                 pollfd.events = POLLIN | POLLOUT;
     316        2533 :                 int nRet = poll(&pollfd, 1, timeout_ms);
     317             : #else
     318             :                 struct timeval tval = MillisToTimeval(timeout_ms);
     319             :                 fd_set fdset;
     320             :                 FD_ZERO(&fdset);
     321             :                 FD_SET(hSocket, &fdset);
     322             :                 int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
     323             : #endif
     324        2533 :                 if (nRet == SOCKET_ERROR) {
     325           0 :                     return IntrRecvError::NetworkError;
     326        2533 :                 }
     327             :             } else {
     328             :                 return IntrRecvError::NetworkError;
     329             :             }
     330             :         }
     331        2597 :         if (interruptSocks5Recv)
     332             :             return IntrRecvError::Interrupted;
     333        2597 :         curTime = GetTimeMillis();
     334             :     }
     335          64 :     return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
     336             : }
     337             : 
     338             : /** Credentials for proxy authentication */
     339           8 : struct ProxyCredentials
     340             : {
     341             :     std::string username;
     342             :     std::string password;
     343             : };
     344             : 
     345             : /** Convert SOCKS5 reply to a an error message */
     346           0 : static std::string Socks5ErrorString(uint8_t err)
     347             : {
     348           0 :     switch(err) {
     349           0 :         case SOCKS5Reply::GENFAILURE:
     350           0 :             return "general failure";
     351           0 :         case SOCKS5Reply::NOTALLOWED:
     352           0 :             return "connection not allowed";
     353           0 :         case SOCKS5Reply::NETUNREACHABLE:
     354           0 :             return "network unreachable";
     355           0 :         case SOCKS5Reply::HOSTUNREACHABLE:
     356           0 :             return "host unreachable";
     357           0 :         case SOCKS5Reply::CONNREFUSED:
     358           0 :             return "connection refused";
     359           0 :         case SOCKS5Reply::TTLEXPIRED:
     360           0 :             return "TTL expired";
     361           0 :         case SOCKS5Reply::CMDUNSUPPORTED:
     362           0 :             return "protocol error";
     363           0 :         case SOCKS5Reply::ATYPEUNSUPPORTED:
     364           0 :             return "address type not supported";
     365           0 :         default:
     366           0 :             return "unknown";
     367             :     }
     368             : }
     369             : 
     370             : /** Connect using SOCKS5 (as described in RFC1928) */
     371          15 : bool static Socks5(std::string strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
     372             : {
     373          15 :     IntrRecvError recvr;
     374          15 :     LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
     375          15 :     if (strDest.size() > 255) {
     376           0 :         return error("Hostname too long");
     377             :     }
     378             :     // Accepted authentication methods
     379          30 :     std::vector<uint8_t> vSocks5Init;
     380          15 :     vSocks5Init.push_back(SOCKSVersion::SOCKS5);
     381          15 :     if (auth) {
     382           8 :         vSocks5Init.push_back(0x02); // Number of methods
     383           8 :         vSocks5Init.push_back(SOCKS5Method::NOAUTH);
     384           8 :         vSocks5Init.push_back(SOCKS5Method::USER_PASS);
     385             :     } else {
     386           7 :         vSocks5Init.push_back(0x01); // Number of methods
     387           7 :         vSocks5Init.push_back(SOCKS5Method::NOAUTH);
     388             :     }
     389          15 :     ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
     390          15 :     if (ret != (ssize_t)vSocks5Init.size()) {
     391           0 :         return error("Error sending to proxy");
     392             :     }
     393          15 :     uint8_t pchRet1[2];
     394          15 :     if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
     395           0 :         LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
     396             :         return false;
     397             :     }
     398          15 :     if (pchRet1[0] != SOCKSVersion::SOCKS5) {
     399           0 :         return error("Proxy failed to initialize");
     400             :     }
     401          15 :     if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
     402             :         // Perform username/password authentication (as described in RFC1929)
     403           8 :         std::vector<uint8_t> vAuth;
     404           4 :         vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
     405           4 :         if (auth->username.size() > 255 || auth->password.size() > 255)
     406           0 :             return error("Proxy username or password too long");
     407           4 :         vAuth.push_back(auth->username.size());
     408           4 :         vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
     409           4 :         vAuth.push_back(auth->password.size());
     410           4 :         vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
     411           4 :         ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
     412           4 :         if (ret != (ssize_t)vAuth.size()) {
     413           0 :             return error("Error sending authentication to proxy");
     414             :         }
     415           4 :         LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
     416           4 :         uint8_t pchRetA[2];
     417           4 :         if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
     418           0 :             return error("Error reading proxy authentication response");
     419             :         }
     420           4 :         if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
     421           0 :             return error("Proxy authentication unsuccessful");
     422             :         }
     423          11 :     } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
     424             :         // Perform no authentication
     425             :     } else {
     426           0 :         return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
     427             :     }
     428          30 :     std::vector<uint8_t> vSocks5;
     429          15 :     vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
     430          15 :     vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
     431          15 :     vSocks5.push_back(0x00); // RSV Reserved must be 0
     432          15 :     vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
     433          15 :     vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
     434          15 :     vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
     435          15 :     vSocks5.push_back((port >> 8) & 0xFF);
     436          15 :     vSocks5.push_back((port >> 0) & 0xFF);
     437          15 :     ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
     438          15 :     if (ret != (ssize_t)vSocks5.size()) {
     439           0 :         return error("Error sending to proxy");
     440             :     }
     441          15 :     uint8_t pchRet2[4];
     442          15 :     if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
     443           0 :         if (recvr == IntrRecvError::Timeout) {
     444             :             /* If a timeout happens here, this effectively means we timed out while connecting
     445             :              * to the remote node. This is very common for Tor, so do not print an
     446             :              * error message. */
     447             :             return false;
     448             :         } else {
     449           0 :             return error("Error while reading proxy response");
     450             :         }
     451             :     }
     452          15 :     if (pchRet2[0] != SOCKSVersion::SOCKS5) {
     453           0 :         return error("Proxy failed to accept request");
     454             :     }
     455          15 :     if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
     456             :         // Failures to connect to a peer that are not proxy errors
     457           0 :         LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
     458           0 :         return false;
     459             :     }
     460          15 :     if (pchRet2[2] != 0x00) { // Reserved field must be 0
     461           0 :         return error("Error: malformed proxy response");
     462             :     }
     463          15 :     uint8_t pchRet3[256];
     464          15 :     switch (pchRet2[3])
     465             :     {
     466          15 :         case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
     467           0 :         case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
     468           0 :         case SOCKS5Atyp::DOMAINNAME:
     469           0 :         {
     470           0 :             recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
     471           0 :             if (recvr != IntrRecvError::OK) {
     472           0 :                 return error("Error reading from proxy");
     473             :             }
     474           0 :             int nRecv = pchRet3[0];
     475           0 :             recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
     476             :             break;
     477             :         }
     478           0 :         default: return error("Error: malformed proxy response");
     479             :     }
     480          15 :     if (recvr != IntrRecvError::OK) {
     481           0 :         return error("Error reading from proxy");
     482             :     }
     483          15 :     if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
     484           0 :         return error("Error reading from proxy");
     485             :     }
     486          15 :     LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
     487             :     return true;
     488             : }
     489             : 
     490        1095 : SOCKET CreateSocket(const CService& addrConnect)
     491             : {
     492        1095 :     struct sockaddr_storage sockaddr;
     493        1095 :     socklen_t len = sizeof(sockaddr);
     494        1095 :     if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
     495           0 :         LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
     496           0 :         return INVALID_SOCKET;
     497             :     }
     498             : 
     499        1095 :     SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
     500        1095 :     if (hSocket == INVALID_SOCKET)
     501             :         return INVALID_SOCKET;
     502             : 
     503        1095 :     if (!IsSelectableSocket(hSocket)) {
     504             :         CloseSocket(hSocket);
     505             :         LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
     506             :         return INVALID_SOCKET;
     507             :     }
     508             : 
     509             : #ifdef SO_NOSIGPIPE
     510             :     int set = 1;
     511             :     // Different way of disabling SIGPIPE on BSD
     512             :     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
     513             : #endif
     514             : 
     515             :     // Set to non-blocking
     516        1095 :     if (!SetSocketNonBlocking(hSocket, true)) {
     517           0 :         CloseSocket(hSocket);
     518           0 :         LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
     519             :     }
     520        1095 :     return hSocket;
     521             : }
     522             : 
     523             : template<typename... Args>
     524           1 : static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) {
     525           1 :     std::string error_message = tfm::format(fmt, args...);
     526           1 :     if (manual_connection) {
     527           1 :         LogPrintf("%s\n", error_message);
     528             :     } else {
     529           0 :         LogPrint(BCLog::NET, "%s\n", error_message);
     530             :     }
     531           1 : }
     532             : 
     533         749 : bool ConnectSocketDirectly(const CService& addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
     534             : {
     535         749 :     struct sockaddr_storage sockaddr;
     536         749 :     socklen_t len = sizeof(sockaddr);
     537         749 :     if (hSocket == INVALID_SOCKET) {
     538           0 :         LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
     539           0 :         return false;
     540             :     }
     541         749 :     if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
     542           0 :         LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
     543           0 :         return false;
     544             :     }
     545         749 :     if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) {
     546         749 :         int nErr = WSAGetLastError();
     547             :         // WSAEINVAL is here because some legacy version of winsock uses it
     548         749 :         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
     549             : #ifdef USE_POLL
     550         749 :             struct pollfd pollfd = {};
     551         749 :             pollfd.fd = hSocket;
     552         749 :             pollfd.events = POLLIN | POLLOUT;
     553         749 :             int nRet = poll(&pollfd, 1, nTimeout);
     554             : #else
     555             :             struct timeval timeout = MillisToTimeval(nTimeout);
     556             :             fd_set fdset;
     557             :             FD_ZERO(&fdset);
     558             :             FD_SET(hSocket, &fdset);
     559             :             int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
     560             : #endif
     561         749 :             if (nRet == 0) {
     562          24 :                 LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
     563          13 :                 return false;
     564             :             }
     565         737 :             if (nRet == SOCKET_ERROR) {
     566           0 :                 LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     567           0 :                 return false;
     568             :             }
     569         737 :             socklen_t nRetSize = sizeof(nRet);
     570         737 :             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
     571             :             {
     572           0 :                 LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     573           0 :                 return false;
     574             :             }
     575         737 :             if (nRet != 0) {
     576           2 :                 LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
     577           1 :                 return false;
     578         736 :             }
     579             :         }
     580             : #ifdef WIN32
     581             :         else if (WSAGetLastError() != WSAEISCONN)
     582             : #else
     583             :         else
     584             : #endif
     585             :         {
     586           0 :             LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     587           0 :             return false;
     588             :         }
     589             :     }
     590             :     return true;
     591             : }
     592             : 
     593          13 : bool SetProxy(enum Network net, const proxyType &addrProxy)
     594             : {
     595          13 :     assert(net >= 0 && net < NET_MAX);
     596          13 :     if (!addrProxy.IsValid())
     597             :         return false;
     598          13 :     LOCK(cs_proxyInfos);
     599          13 :     proxyInfo[net] = addrProxy;
     600          13 :     return true;
     601             : }
     602             : 
     603        4369 : bool GetProxy(enum Network net, proxyType& proxyInfoOut)
     604             : {
     605        4369 :     assert(net >= 0 && net < NET_MAX);
     606        8738 :     LOCK(cs_proxyInfos);
     607        4369 :     if (!proxyInfo[net].IsValid())
     608             :         return false;
     609          41 :     proxyInfoOut = proxyInfo[net];
     610          41 :     return true;
     611             : }
     612             : 
     613           4 : bool SetNameProxy(const proxyType &addrProxy)
     614             : {
     615           4 :     if (!addrProxy.IsValid())
     616             :         return false;
     617           4 :     LOCK(cs_proxyInfos);
     618           4 :     nameProxy = addrProxy;
     619           4 :     return true;
     620             : }
     621             : 
     622           4 : bool GetNameProxy(proxyType &nameProxyOut)
     623             : {
     624           8 :     LOCK(cs_proxyInfos);
     625           4 :     if (!nameProxy.IsValid())
     626             :         return false;
     627           4 :     nameProxyOut = nameProxy;
     628           4 :     return true;
     629             : }
     630             : 
     631         694 : bool HaveNameProxy()
     632             : {
     633         694 :     LOCK(cs_proxyInfos);
     634        1388 :     return nameProxy.IsValid();
     635             : }
     636             : 
     637          11 : bool IsProxy(const CNetAddr& addr)
     638             : {
     639          22 :     LOCK(cs_proxyInfos);
     640          88 :     for (int i = 0; i < NET_MAX; i++) {
     641          77 :         if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy))
     642             :             return true;
     643             :     }
     644             :     return false;
     645             : }
     646             : 
     647          15 : bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
     648             : {
     649             :     // first connect to proxy server
     650          15 :     if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
     651           0 :         if (outProxyConnectionFailed)
     652           0 :             *outProxyConnectionFailed = true;
     653           0 :         return false;
     654             :     }
     655             :     // do socks negotiation
     656          15 :     if (proxy.randomize_credentials) {
     657          16 :         ProxyCredentials random_auth;
     658           8 :         static std::atomic_int counter;
     659           8 :         random_auth.username = random_auth.password = strprintf("%i", counter++);
     660          20 :         if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
     661           0 :             return false;
     662             :         }
     663             :     } else {
     664          10 :         if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
     665           0 :             return false;
     666             :         }
     667             :     }
     668             :     return true;
     669             : }
     670             : 
     671         151 : bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
     672             : {
     673         151 :     if (!ValidAsCString(strSubnet)) {
     674             :         return false;
     675             :     }
     676         145 :     size_t slash = strSubnet.find_last_of('/');
     677         145 :     std::vector<CNetAddr> vIP;
     678             : 
     679         290 :     std::string strAddress = strSubnet.substr(0, slash);
     680         145 :     if (LookupHost(strAddress, vIP, 1, false))
     681             :     {
     682         143 :         CNetAddr network = vIP[0];
     683         141 :         if (slash != strSubnet.npos) {
     684          83 :             std::string strNetmask = strSubnet.substr(slash + 1);
     685          81 :             uint8_t n;
     686          81 :             if (ParseUInt8(strNetmask, &n)) {
     687             :                 // If valid number, assume CIDR variable-length subnet masking
     688          70 :                 ret = CSubNet(network, n);
     689         114 :                 return ret.IsValid();
     690             :             } else // If not a valid number, try full netmask syntax
     691             :             {
     692             :                 // Never allow lookup for netmask
     693          46 :                 if (LookupHost(strNetmask, vIP, 1, false)) {
     694          88 :                     ret = CSubNet(network, vIP[0]);
     695          44 :                     return ret.IsValid();
     696             :                 }
     697             :             }
     698             :         } else {
     699         120 :             ret = CSubNet(network);
     700          60 :             return ret.IsValid();
     701             :         }
     702             :     }
     703             :     return false;
     704             : }
     705             : 
     706             : #ifdef WIN32
     707             : std::string NetworkErrorString(int err)
     708             : {
     709             :     wchar_t buf[256];
     710             :     buf[0] = 0;
     711             :     if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
     712             :             nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     713             :             buf, ARRAYSIZE(buf), nullptr))
     714             :     {
     715             :         const auto& bufConvert = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf);
     716             :         return strprintf("%s (%d)", bufConvert, err);
     717             :     } else {
     718             :         return strprintf("Unknown error (%d)", err);
     719             :     }
     720             : }
     721             : #else
     722          52 : std::string NetworkErrorString(int err)
     723             : {
     724          52 :     char buf[256];
     725          52 :     buf[0] = 0;
     726             : /* Too bad there are two incompatible implementations of the
     727             :      * thread-safe strerror. */
     728          52 :     const char *s;
     729             : #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
     730          52 :     s = strerror_r(err, buf, sizeof(buf));
     731             : #else                    /* POSIX variant always returns message in buffer */
     732             :     s = buf;
     733             :     if (strerror_r(err, buf, sizeof(buf)))
     734             :         buf[0] = 0;
     735             : #endif
     736          52 :     return strprintf("%s (%d)", s, err);
     737             : }
     738             : #endif
     739             : 
     740        3350 : bool CloseSocket(SOCKET& hSocket)
     741             : {
     742        3350 :     if (hSocket == INVALID_SOCKET)
     743             :         return false;
     744             : #ifdef WIN32
     745             :     int ret = closesocket(hSocket);
     746             : #else
     747        1886 :     int ret = close(hSocket);
     748             : #endif
     749        1886 :     hSocket = INVALID_SOCKET;
     750        1886 :     return ret != SOCKET_ERROR;
     751             : }
     752             : 
     753        1095 : bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
     754             : {
     755        1095 :     if (fNonBlocking) {
     756             : #ifdef WIN32
     757             :         u_long nOne = 1;
     758             :         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
     759             : #else
     760        1095 :         int fFlags = fcntl(hSocket, F_GETFL, 0);
     761        1095 :         if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
     762             : #endif
     763           0 :             CloseSocket(hSocket);
     764           0 :             return false;
     765             :         }
     766             :     } else {
     767             : #ifdef WIN32
     768             :         u_long nZero = 0;
     769             :         if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
     770             : #else
     771           0 :         int fFlags = fcntl(hSocket, F_GETFL, 0);
     772           0 :         if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
     773             : #endif
     774           0 :             CloseSocket(hSocket);
     775           0 :             return false;
     776             :         }
     777             :     }
     778             : 
     779             :     return true;
     780             : }
     781             : 
     782        1205 : void InterruptSocks5(bool interrupt)
     783             : {
     784        1205 :     interruptSocks5Recv = interrupt;
     785        1205 : }

Generated by: LCOV version 1.14