LCOV - code coverage report
Current view: top level - src - netbase.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 288 373 77.2 %
Date: 2025-04-02 01:23:23 Functions: 27 29 93.1 %

          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       12803 : std::string GetNetworkName(enum Network net)
      56             : {
      57       12803 :     switch (net) {
      58         319 :         case NET_UNROUTABLE: return "unroutable";
      59       10039 :         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      600004 : void SplitHostPort(std::string in, int& portOut, std::string& hostOut)
      72             : {
      73      600004 :     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      600004 :     bool fHaveColon = colon != in.npos;
      76      600004 :     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      600004 :     bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos);
      78      600004 :     if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
      79        2027 :         int32_t n;
      80        4054 :         if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
      81        1939 :             in = in.substr(0, colon);
      82        1939 :             portOut = n;
      83             :         }
      84             :     }
      85      600004 :     if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']')
      86          18 :         hostOut = in.substr(1, in.size() - 2);
      87             :     else
      88      599986 :         hostOut = in;
      89      600004 : }
      90             : 
      91      618410 : bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
      92             : {
      93      618410 :     vIP.clear();
      94             : 
      95      618410 :     if (!ValidAsCString(name)) {
      96             :         return false;
      97             :     }
      98             : 
      99      618410 :     {
     100      618410 :         CNetAddr addr;
     101      618410 :         if (addr.SetSpecial(name)) {
     102           7 :             vIP.push_back(addr);
     103           7 :             return true;
     104             :         }
     105             :     }
     106             : 
     107      618403 :     struct addrinfo aiHint;
     108      618403 :     memset(&aiHint, 0, sizeof(struct addrinfo));
     109             : 
     110      618403 :     aiHint.ai_socktype = SOCK_STREAM;
     111      618403 :     aiHint.ai_protocol = IPPROTO_TCP;
     112      618403 :     aiHint.ai_family = AF_UNSPEC;
     113             : #ifdef WIN32
     114             :     aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
     115             : #else
     116      618403 :     aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
     117             : #endif
     118      618403 :     struct addrinfo* aiRes = nullptr;
     119      618403 :     int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
     120      618403 :     if (nErr)
     121             :         return false;
     122             : 
     123      618295 :     struct addrinfo* aiTrav = aiRes;
     124     1236590 :     while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) {
     125     1236590 :         CNetAddr resolved;
     126      618295 :         if (aiTrav->ai_family == AF_INET) {
     127      617458 :             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
     128      617458 :             resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
     129             :         }
     130             : 
     131      618295 :         if (aiTrav->ai_family == AF_INET6) {
     132         837 :             assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
     133         837 :             struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
     134         837 :             resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
     135             :         }
     136             :         /* Never allow resolving to an internal address. Consider any such result invalid */
     137      618295 :         if (!resolved.IsInternal()) {
     138      618294 :             vIP.push_back(resolved);
     139             :         }
     140             : 
     141      618295 :         aiTrav = aiTrav->ai_next;
     142             :     }
     143             : 
     144      618295 :     freeaddrinfo(aiRes);
     145             : 
     146      618295 :     return (vIP.size() > 0);
     147             : }
     148             : 
     149       19683 : bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
     150             : {
     151       19683 :     if (!ValidAsCString(name)) {
     152             :         return false;
     153             :     }
     154       39366 :     std::string strHost = name;
     155       19683 :     if (strHost.empty())
     156             :         return false;
     157       19682 :     if (strHost.front() == '[' && strHost.back() == ']') {
     158           1 :         strHost = strHost.substr(1, strHost.size() - 2);
     159             :     }
     160             : 
     161       19682 :     return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup);
     162             : }
     163             : 
     164       19495 : bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
     165             : {
     166       19495 :     if (!ValidAsCString(name)) {
     167             :         return false;
     168             :     }
     169       38984 :     std::vector<CNetAddr> vIP;
     170       19492 :     LookupHost(name, vIP, 1, fAllowLookup);
     171       19492 :     if (vIP.empty())
     172             :         return false;
     173       19394 :     addr = vIP.front();
     174       19394 :     return true;
     175             : }
     176             : 
     177      598728 : bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
     178             : {
     179      598728 :     if (name.empty() || !ValidAsCString(name)) {
     180             :         return false;
     181             :     }
     182      598728 :     int port = portDefault;
     183     1197460 :     std::string hostname;
     184     1197460 :     SplitHostPort(name, port, hostname);
     185             : 
     186     1197460 :     std::vector<CNetAddr> vIP;
     187      598728 :     bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
     188      598728 :     if (!fRet)
     189             :         return false;
     190      598722 :     vAddr.resize(vIP.size());
     191     1197446 :     for (unsigned int i = 0; i < vIP.size(); i++)
     192      598722 :         vAddr[i] = CService(vIP[i], port);
     193             :     return true;
     194             : }
     195             : 
     196      598058 : bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup)
     197             : {
     198      598058 :     if (!ValidAsCString(name)) {
     199             :         return false;
     200             :     }
     201     1196110 :     std::vector<CService> vService;
     202      598057 :     bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1);
     203      598057 :     if (!fRet)
     204             :         return false;
     205      598055 :     addr = vService[0];
     206      598055 :     return true;
     207             : }
     208             : 
     209      590658 : CService LookupNumeric(const std::string& name, int portDefault)
     210             : {
     211      590658 :     if (!ValidAsCString(name)) {
     212           0 :         return {};
     213             :     }
     214     1181314 :     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      590658 :     if (!Lookup(name, addr, portDefault, false))
     218           2 :         addr = CService();
     219      590658 :     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      117986 :     while (len > 0 && curTime < endTime) {
     299      117922 :         ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
     300      117922 :         if (ret > 0) {
     301          64 :             len -= ret;
     302          64 :             data += ret;
     303      117858 :         } else if (ret == 0) { // Unexpected disconnection
     304             :             return IntrRecvError::Disconnected;
     305             :         } else { // Other error or blocking
     306      117858 :             int nErr = WSAGetLastError();
     307      117858 :             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
     308      117858 :                 if (!IsSelectableSocket(hSocket)) {
     309           0 :                     return IntrRecvError::NetworkError;
     310             :                 }
     311      117858 :                 int timeout_ms = std::min(endTime - curTime, maxWait);
     312             : #ifdef USE_POLL
     313      117858 :                 struct pollfd pollfd = {};
     314      117858 :                 pollfd.fd = hSocket;
     315      117858 :                 pollfd.events = POLLIN | POLLOUT;
     316      117858 :                 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      117858 :                 if (nRet == SOCKET_ERROR) {
     325           0 :                     return IntrRecvError::NetworkError;
     326      117858 :                 }
     327             :             } else {
     328             :                 return IntrRecvError::NetworkError;
     329             :             }
     330             :         }
     331      117922 :         if (interruptSocks5Recv)
     332             :             return IntrRecvError::Interrupted;
     333      117922 :         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        1072 : SOCKET CreateSocket(const CService& addrConnect)
     491             : {
     492        1072 :     struct sockaddr_storage sockaddr;
     493        1072 :     socklen_t len = sizeof(sockaddr);
     494        1072 :     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        1072 :     SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
     500        1072 :     if (hSocket == INVALID_SOCKET)
     501             :         return INVALID_SOCKET;
     502             : 
     503        1072 :     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             :     // Disable Nagle's algorithm
     515        1072 :     SetSocketNoDelay(hSocket);
     516             : 
     517             :     // Set to non-blocking
     518        1072 :     if (!SetSocketNonBlocking(hSocket, true)) {
     519           0 :         CloseSocket(hSocket);
     520           0 :         LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
     521             :     }
     522        1072 :     return hSocket;
     523             : }
     524             : 
     525             : template<typename... Args>
     526           3 : static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) {
     527           3 :     std::string error_message = tfm::format(fmt, args...);
     528           3 :     if (manual_connection) {
     529           1 :         LogPrintf("%s\n", error_message);
     530             :     } else {
     531           2 :         LogPrint(BCLog::NET, "%s\n", error_message);
     532             :     }
     533           3 : }
     534             : 
     535         726 : bool ConnectSocketDirectly(const CService& addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
     536             : {
     537         726 :     struct sockaddr_storage sockaddr;
     538         726 :     socklen_t len = sizeof(sockaddr);
     539         726 :     if (hSocket == INVALID_SOCKET) {
     540           0 :         LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
     541           0 :         return false;
     542             :     }
     543         726 :     if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
     544           0 :         LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
     545           0 :         return false;
     546             :     }
     547         726 :     if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) {
     548         726 :         int nErr = WSAGetLastError();
     549             :         // WSAEINVAL is here because some legacy version of winsock uses it
     550         726 :         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
     551             : #ifdef USE_POLL
     552         726 :             struct pollfd pollfd = {};
     553         726 :             pollfd.fd = hSocket;
     554         726 :             pollfd.events = POLLIN | POLLOUT;
     555         726 :             int nRet = poll(&pollfd, 1, nTimeout);
     556             : #else
     557             :             struct timeval timeout = MillisToTimeval(nTimeout);
     558             :             fd_set fdset;
     559             :             FD_ZERO(&fdset);
     560             :             FD_SET(hSocket, &fdset);
     561             :             int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
     562             : #endif
     563         726 :             if (nRet == 0) {
     564          24 :                 LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
     565          15 :                 return false;
     566             :             }
     567         714 :             if (nRet == SOCKET_ERROR) {
     568           0 :                 LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     569           0 :                 return false;
     570             :             }
     571         714 :             socklen_t nRetSize = sizeof(nRet);
     572         714 :             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
     573             :             {
     574           0 :                 LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     575           0 :                 return false;
     576             :             }
     577         714 :             if (nRet != 0) {
     578           6 :                 LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
     579           3 :                 return false;
     580         711 :             }
     581             :         }
     582             : #ifdef WIN32
     583             :         else if (WSAGetLastError() != WSAEISCONN)
     584             : #else
     585             :         else
     586             : #endif
     587             :         {
     588           0 :             LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
     589           0 :             return false;
     590             :         }
     591             :     }
     592             :     return true;
     593             : }
     594             : 
     595          13 : bool SetProxy(enum Network net, const proxyType &addrProxy)
     596             : {
     597          13 :     assert(net >= 0 && net < NET_MAX);
     598          13 :     if (!addrProxy.IsValid())
     599             :         return false;
     600          13 :     LOCK(cs_proxyInfos);
     601          13 :     proxyInfo[net] = addrProxy;
     602          13 :     return true;
     603             : }
     604             : 
     605        4346 : bool GetProxy(enum Network net, proxyType& proxyInfoOut)
     606             : {
     607        4346 :     assert(net >= 0 && net < NET_MAX);
     608        8692 :     LOCK(cs_proxyInfos);
     609        4346 :     if (!proxyInfo[net].IsValid())
     610             :         return false;
     611          41 :     proxyInfoOut = proxyInfo[net];
     612          41 :     return true;
     613             : }
     614             : 
     615           4 : bool SetNameProxy(const proxyType &addrProxy)
     616             : {
     617           4 :     if (!addrProxy.IsValid())
     618             :         return false;
     619           4 :     LOCK(cs_proxyInfos);
     620           4 :     nameProxy = addrProxy;
     621           4 :     return true;
     622             : }
     623             : 
     624           4 : bool GetNameProxy(proxyType &nameProxyOut)
     625             : {
     626           8 :     LOCK(cs_proxyInfos);
     627           4 :     if (!nameProxy.IsValid())
     628             :         return false;
     629           4 :     nameProxyOut = nameProxy;
     630           4 :     return true;
     631             : }
     632             : 
     633         671 : bool HaveNameProxy()
     634             : {
     635         671 :     LOCK(cs_proxyInfos);
     636        1342 :     return nameProxy.IsValid();
     637             : }
     638             : 
     639          11 : bool IsProxy(const CNetAddr& addr)
     640             : {
     641          22 :     LOCK(cs_proxyInfos);
     642          88 :     for (int i = 0; i < NET_MAX; i++) {
     643          77 :         if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy))
     644             :             return true;
     645             :     }
     646             :     return false;
     647             : }
     648             : 
     649          15 : bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
     650             : {
     651             :     // first connect to proxy server
     652          15 :     if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
     653           0 :         if (outProxyConnectionFailed)
     654           0 :             *outProxyConnectionFailed = true;
     655           0 :         return false;
     656             :     }
     657             :     // do socks negotiation
     658          15 :     if (proxy.randomize_credentials) {
     659          16 :         ProxyCredentials random_auth;
     660           8 :         static std::atomic_int counter;
     661           8 :         random_auth.username = random_auth.password = strprintf("%i", counter++);
     662          20 :         if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
     663           0 :             return false;
     664             :         }
     665             :     } else {
     666          10 :         if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
     667           0 :             return false;
     668             :         }
     669             :     }
     670             :     return true;
     671             : }
     672             : 
     673         151 : bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
     674             : {
     675         151 :     if (!ValidAsCString(strSubnet)) {
     676             :         return false;
     677             :     }
     678         145 :     size_t slash = strSubnet.find_last_of('/');
     679         145 :     std::vector<CNetAddr> vIP;
     680             : 
     681         290 :     std::string strAddress = strSubnet.substr(0, slash);
     682         145 :     if (LookupHost(strAddress, vIP, 1, false))
     683             :     {
     684         143 :         CNetAddr network = vIP[0];
     685         141 :         if (slash != strSubnet.npos) {
     686          83 :             std::string strNetmask = strSubnet.substr(slash + 1);
     687          81 :             uint8_t n;
     688          81 :             if (ParseUInt8(strNetmask, &n)) {
     689             :                 // If valid number, assume CIDR variable-length subnet masking
     690          70 :                 ret = CSubNet(network, n);
     691         114 :                 return ret.IsValid();
     692             :             } else // If not a valid number, try full netmask syntax
     693             :             {
     694             :                 // Never allow lookup for netmask
     695          46 :                 if (LookupHost(strNetmask, vIP, 1, false)) {
     696          88 :                     ret = CSubNet(network, vIP[0]);
     697          44 :                     return ret.IsValid();
     698             :                 }
     699             :             }
     700             :         } else {
     701         120 :             ret = CSubNet(network);
     702          60 :             return ret.IsValid();
     703             :         }
     704             :     }
     705             :     return false;
     706             : }
     707             : 
     708             : #ifdef WIN32
     709             : std::string NetworkErrorString(int err)
     710             : {
     711             :     wchar_t buf[256];
     712             :     buf[0] = 0;
     713             :     if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
     714             :             nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     715             :             buf, ARRAYSIZE(buf), nullptr))
     716             :     {
     717             :         const auto& bufConvert = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf);
     718             :         return strprintf("%s (%d)", bufConvert, err);
     719             :     } else {
     720             :         return strprintf("Unknown error (%d)", err);
     721             :     }
     722             : }
     723             : #else
     724          28 : std::string NetworkErrorString(int err)
     725             : {
     726          28 :     char buf[256];
     727          28 :     buf[0] = 0;
     728             : /* Too bad there are two incompatible implementations of the
     729             :      * thread-safe strerror. */
     730          28 :     const char *s;
     731             : #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
     732          28 :     s = strerror_r(err, buf, sizeof(buf));
     733             : #else                    /* POSIX variant always returns message in buffer */
     734             :     s = buf;
     735             :     if (strerror_r(err, buf, sizeof(buf)))
     736             :         buf[0] = 0;
     737             : #endif
     738          28 :     return strprintf("%s (%d)", s, err);
     739             : }
     740             : #endif
     741             : 
     742        3274 : bool CloseSocket(SOCKET& hSocket)
     743             : {
     744        3274 :     if (hSocket == INVALID_SOCKET)
     745             :         return false;
     746             : #ifdef WIN32
     747             :     int ret = closesocket(hSocket);
     748             : #else
     749        1838 :     int ret = close(hSocket);
     750             : #endif
     751        1838 :     hSocket = INVALID_SOCKET;
     752        1838 :     return ret != SOCKET_ERROR;
     753             : }
     754             : 
     755        1072 : bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
     756             : {
     757        1072 :     if (fNonBlocking) {
     758             : #ifdef WIN32
     759             :         u_long nOne = 1;
     760             :         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
     761             : #else
     762        1072 :         int fFlags = fcntl(hSocket, F_GETFL, 0);
     763        1072 :         if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
     764             : #endif
     765           0 :             CloseSocket(hSocket);
     766           0 :             return false;
     767             :         }
     768             :     } else {
     769             : #ifdef WIN32
     770             :         u_long nZero = 0;
     771             :         if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
     772             : #else
     773           0 :         int fFlags = fcntl(hSocket, F_GETFL, 0);
     774           0 :         if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
     775             : #endif
     776           0 :             CloseSocket(hSocket);
     777           0 :             return false;
     778             :         }
     779             :     }
     780             : 
     781             :     return true;
     782             : }
     783             : 
     784        1832 : bool SetSocketNoDelay(SOCKET& hSocket)
     785             : {
     786        1832 :     int set = 1;
     787        1832 :     int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
     788        1832 :     return rc == 0;
     789             : }
     790             : 
     791        1205 : void InterruptSocks5(bool interrupt)
     792             : {
     793        1205 :     interruptSocks5Recv = interrupt;
     794        1205 : }

Generated by: LCOV version 1.14