Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2020 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #include <netbase.h>
# 7 : :
# 8 : : #include <sync.h>
# 9 : : #include <tinyformat.h>
# 10 : : #include <util/strencodings.h>
# 11 : : #include <util/string.h>
# 12 : : #include <util/system.h>
# 13 : :
# 14 : : #include <atomic>
# 15 : : #include <cstdint>
# 16 : : #include <limits>
# 17 : :
# 18 : : #ifndef WIN32
# 19 : : #include <fcntl.h>
# 20 : : #else
# 21 : : #include <codecvt>
# 22 : : #endif
# 23 : :
# 24 : : #ifdef USE_POLL
# 25 : : #include <poll.h>
# 26 : : #endif
# 27 : :
# 28 : : #if !defined(MSG_NOSIGNAL)
# 29 : : #define MSG_NOSIGNAL 0
# 30 : : #endif
# 31 : :
# 32 : : // Settings
# 33 : : static Mutex g_proxyinfo_mutex;
# 34 : : static proxyType proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex);
# 35 : : static proxyType nameProxy GUARDED_BY(g_proxyinfo_mutex);
# 36 : : int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
# 37 : : bool fNameLookup = DEFAULT_NAME_LOOKUP;
# 38 : :
# 39 : : // Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
# 40 : : static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
# 41 : : static std::atomic<bool> interruptSocks5Recv(false);
# 42 : :
# 43 : 24 : enum Network ParseNetwork(const std::string& net_in) {
# 44 : 24 : std::string net = ToLower(net_in);
# 45 : 24 : if (net == "ipv4") return NET_IPV4;
# 46 : 20 : if (net == "ipv6") return NET_IPV6;
# 47 : 16 : if (net == "onion") return NET_ONION;
# 48 : 12 : if (net == "tor") {
# 49 : 4 : LogPrintf("Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n");
# 50 : 4 : return NET_ONION;
# 51 : 4 : }
# 52 : 8 : return NET_UNROUTABLE;
# 53 : 8 : }
# 54 : :
# 55 : 141 : std::string GetNetworkName(enum Network net) {
# 56 : 141 : switch(net)
# 57 : 141 : {
# 58 : 47 : case NET_IPV4: return "ipv4";
# 59 : 47 : case NET_IPV6: return "ipv6";
# 60 : 47 : case NET_ONION: return "onion";
# 61 : 0 : default: return "";
# 62 : 141 : }
# 63 : 141 : }
# 64 : :
# 65 : : bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
# 66 : 219947 : {
# 67 : 219947 : vIP.clear();
# 68 : 219947 :
# 69 : 219947 : if (!ValidAsCString(name)) {
# 70 : 0 : return false;
# 71 : 0 : }
# 72 : 219947 :
# 73 : 219947 : {
# 74 : 219947 : CNetAddr addr;
# 75 : 219947 : // From our perspective, onion addresses are not hostnames but rather
# 76 : 219947 : // direct encodings of CNetAddr much like IPv4 dotted-decimal notation
# 77 : 219947 : // or IPv6 colon-separated hextet notation. Since we can't use
# 78 : 219947 : // getaddrinfo to decode them and it wouldn't make sense to resolve
# 79 : 219947 : // them, we return a network address representing it instead. See
# 80 : 219947 : // CNetAddr::SetSpecial(const std::string&) for more details.
# 81 : 219947 : if (addr.SetSpecial(name)) {
# 82 : 9 : vIP.push_back(addr);
# 83 : 9 : return true;
# 84 : 9 : }
# 85 : 219938 : }
# 86 : 219938 :
# 87 : 219938 : struct addrinfo aiHint;
# 88 : 219938 : memset(&aiHint, 0, sizeof(struct addrinfo));
# 89 : 219938 :
# 90 : 219938 : // We want a TCP port, which is a streaming socket type
# 91 : 219938 : aiHint.ai_socktype = SOCK_STREAM;
# 92 : 219938 : aiHint.ai_protocol = IPPROTO_TCP;
# 93 : 219938 : // We don't care which address family (IPv4 or IPv6) is returned
# 94 : 219938 : aiHint.ai_family = AF_UNSPEC;
# 95 : 219938 : // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only
# 96 : 219938 : // return addresses whose family we have an address configured for.
# 97 : 219938 : //
# 98 : 219938 : // If we don't allow lookups, then use the AI_NUMERICHOST flag for
# 99 : 219938 : // getaddrinfo to only decode numerical network addresses and suppress
# 100 : 219938 : // hostname lookups.
# 101 : 219938 : aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
# 102 : 219938 : struct addrinfo *aiRes = nullptr;
# 103 : 219938 : int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
# 104 : 219938 : if (nErr)
# 105 : 27 : return false;
# 106 : 219911 :
# 107 : 219911 : // Traverse the linked list starting with aiTrav, add all non-internal
# 108 : 219911 : // IPv4,v6 addresses to vIP while respecting nMaxSolutions.
# 109 : 219911 : struct addrinfo *aiTrav = aiRes;
# 110 : 439822 : while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
# 111 : 219911 : {
# 112 : 219911 : CNetAddr resolved;
# 113 : 219911 : if (aiTrav->ai_family == AF_INET)
# 114 : 219911 : {
# 115 : 218712 : assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
# 116 : 218712 : resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
# 117 : 218712 : }
# 118 : 219911 :
# 119 : 219911 : if (aiTrav->ai_family == AF_INET6)
# 120 : 219911 : {
# 121 : 1199 : assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
# 122 : 1199 : struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
# 123 : 1199 : resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
# 124 : 1199 : }
# 125 : 219911 : /* Never allow resolving to an internal address. Consider any such result invalid */
# 126 : 219911 : if (!resolved.IsInternal()) {
# 127 : 219909 : vIP.push_back(resolved);
# 128 : 219909 : }
# 129 : 219911 :
# 130 : 219911 : aiTrav = aiTrav->ai_next;
# 131 : 219911 : }
# 132 : 219911 :
# 133 : 219911 : freeaddrinfo(aiRes);
# 134 : 219911 :
# 135 : 219911 : return (vIP.size() > 0);
# 136 : 219911 : }
# 137 : :
# 138 : : /**
# 139 : : * Resolve a host string to its corresponding network addresses.
# 140 : : *
# 141 : : * @param name The string representing a host. Could be a name or a numerical
# 142 : : * IP address (IPv6 addresses in their bracketed form are
# 143 : : * allowed).
# 144 : : * @param[out] vIP The resulting network addresses to which the specified host
# 145 : : * string resolved.
# 146 : : *
# 147 : : * @returns Whether or not the specified host string successfully resolved to
# 148 : : * any resulting network addresses.
# 149 : : *
# 150 : : * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
# 151 : : * for additional parameter descriptions.
# 152 : : */
# 153 : : bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
# 154 : 15461 : {
# 155 : 15461 : if (!ValidAsCString(name)) {
# 156 : 0 : return false;
# 157 : 0 : }
# 158 : 15461 : std::string strHost = name;
# 159 : 15461 : if (strHost.empty())
# 160 : 2 : return false;
# 161 : 15459 : if (strHost.front() == '[' && strHost.back() == ']') {
# 162 : 0 : strHost = strHost.substr(1, strHost.size() - 2);
# 163 : 0 : }
# 164 : 15459 :
# 165 : 15459 : return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup);
# 166 : 15459 : }
# 167 : :
# 168 : : /**
# 169 : : * Resolve a host string to its first corresponding network address.
# 170 : : *
# 171 : : * @see LookupHost(const std::string&, std::vector<CNetAddr>&, unsigned int, bool) for
# 172 : : * additional parameter descriptions.
# 173 : : */
# 174 : : bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
# 175 : 15142 : {
# 176 : 15142 : if (!ValidAsCString(name)) {
# 177 : 6 : return false;
# 178 : 6 : }
# 179 : 15136 : std::vector<CNetAddr> vIP;
# 180 : 15136 : LookupHost(name, vIP, 1, fAllowLookup);
# 181 : 15136 : if(vIP.empty())
# 182 : 6 : return false;
# 183 : 15130 : addr = vIP.front();
# 184 : 15130 : return true;
# 185 : 15130 : }
# 186 : :
# 187 : : /**
# 188 : : * Resolve a service string to its corresponding service.
# 189 : : *
# 190 : : * @param name The string representing a service. Could be a name or a
# 191 : : * numerical IP address (IPv6 addresses should be in their
# 192 : : * disambiguated bracketed form), optionally followed by a port
# 193 : : * number. (e.g. example.com:8333 or
# 194 : : * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
# 195 : : * @param[out] vAddr The resulting services to which the specified service string
# 196 : : * resolved.
# 197 : : * @param portDefault The default port for resulting services if not specified
# 198 : : * by the service string.
# 199 : : * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
# 200 : : * external queries may be performed.
# 201 : : * @param nMaxSolutions The maximum number of results we want, specifying 0
# 202 : : * means "as many solutions as we get."
# 203 : : *
# 204 : : * @returns Whether or not the service string successfully resolved to any
# 205 : : * resulting services.
# 206 : : */
# 207 : : bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
# 208 : 204492 : {
# 209 : 204492 : if (name.empty() || !ValidAsCString(name)) {
# 210 : 4 : return false;
# 211 : 4 : }
# 212 : 204488 : int port = portDefault;
# 213 : 204488 : std::string hostname;
# 214 : 204488 : SplitHostPort(name, port, hostname);
# 215 : 204488 :
# 216 : 204488 : std::vector<CNetAddr> vIP;
# 217 : 204488 : bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
# 218 : 204488 : if (!fRet)
# 219 : 10 : return false;
# 220 : 204478 : vAddr.resize(vIP.size());
# 221 : 408956 : for (unsigned int i = 0; i < vIP.size(); i++)
# 222 : 204478 : vAddr[i] = CService(vIP[i], port);
# 223 : 204478 : return true;
# 224 : 204478 : }
# 225 : :
# 226 : : /**
# 227 : : * Resolve a service string to its first corresponding service.
# 228 : : *
# 229 : : * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
# 230 : : * for additional parameter descriptions.
# 231 : : */
# 232 : : bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup)
# 233 : 204247 : {
# 234 : 204247 : if (!ValidAsCString(name)) {
# 235 : 2 : return false;
# 236 : 2 : }
# 237 : 204245 : std::vector<CService> vService;
# 238 : 204245 : bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1);
# 239 : 204245 : if (!fRet)
# 240 : 10 : return false;
# 241 : 204235 : addr = vService[0];
# 242 : 204235 : return true;
# 243 : 204235 : }
# 244 : :
# 245 : : /**
# 246 : : * Resolve a service string with a numeric IP to its first corresponding
# 247 : : * service.
# 248 : : *
# 249 : : * @returns The resulting CService if the resolution was successful, [::]:0
# 250 : : * otherwise.
# 251 : : *
# 252 : : * @see Lookup(const char *, CService&, int, bool) for additional parameter
# 253 : : * descriptions.
# 254 : : */
# 255 : : CService LookupNumeric(const std::string& name, int portDefault)
# 256 : 190454 : {
# 257 : 190454 : if (!ValidAsCString(name)) {
# 258 : 0 : return {};
# 259 : 0 : }
# 260 : 190454 : CService addr;
# 261 : 190454 : // "1.2:345" will fail to resolve the ip, but will still set the port.
# 262 : 190454 : // If the ip fails to resolve, re-init the result.
# 263 : 190454 : if(!Lookup(name, addr, portDefault, false))
# 264 : 5 : addr = CService();
# 265 : 190454 : return addr;
# 266 : 190454 : }
# 267 : :
# 268 : : struct timeval MillisToTimeval(int64_t nTimeout)
# 269 : 265 : {
# 270 : 265 : struct timeval timeout;
# 271 : 265 : timeout.tv_sec = nTimeout / 1000;
# 272 : 265 : timeout.tv_usec = (nTimeout % 1000) * 1000;
# 273 : 265 : return timeout;
# 274 : 265 : }
# 275 : :
# 276 : : /** SOCKS version */
# 277 : : enum SOCKSVersion: uint8_t {
# 278 : : SOCKS4 = 0x04,
# 279 : : SOCKS5 = 0x05
# 280 : : };
# 281 : :
# 282 : : /** Values defined for METHOD in RFC1928 */
# 283 : : enum SOCKS5Method: uint8_t {
# 284 : : NOAUTH = 0x00, //!< No authentication required
# 285 : : GSSAPI = 0x01, //!< GSSAPI
# 286 : : USER_PASS = 0x02, //!< Username/password
# 287 : : NO_ACCEPTABLE = 0xff, //!< No acceptable methods
# 288 : : };
# 289 : :
# 290 : : /** Values defined for CMD in RFC1928 */
# 291 : : enum SOCKS5Command: uint8_t {
# 292 : : CONNECT = 0x01,
# 293 : : BIND = 0x02,
# 294 : : UDP_ASSOCIATE = 0x03
# 295 : : };
# 296 : :
# 297 : : /** Values defined for REP in RFC1928 */
# 298 : : enum SOCKS5Reply: uint8_t {
# 299 : : SUCCEEDED = 0x00, //!< Succeeded
# 300 : : GENFAILURE = 0x01, //!< General failure
# 301 : : NOTALLOWED = 0x02, //!< Connection not allowed by ruleset
# 302 : : NETUNREACHABLE = 0x03, //!< Network unreachable
# 303 : : HOSTUNREACHABLE = 0x04, //!< Network unreachable
# 304 : : CONNREFUSED = 0x05, //!< Connection refused
# 305 : : TTLEXPIRED = 0x06, //!< TTL expired
# 306 : : CMDUNSUPPORTED = 0x07, //!< Command not supported
# 307 : : ATYPEUNSUPPORTED = 0x08, //!< Address type not supported
# 308 : : };
# 309 : :
# 310 : : /** Values defined for ATYPE in RFC1928 */
# 311 : : enum SOCKS5Atyp: uint8_t {
# 312 : : IPV4 = 0x01,
# 313 : : DOMAINNAME = 0x03,
# 314 : : IPV6 = 0x04,
# 315 : : };
# 316 : :
# 317 : : /** Status codes that can be returned by InterruptibleRecv */
# 318 : : enum class IntrRecvError {
# 319 : : OK,
# 320 : : Timeout,
# 321 : : Disconnected,
# 322 : : NetworkError,
# 323 : : Interrupted
# 324 : : };
# 325 : :
# 326 : : /**
# 327 : : * Try to read a specified number of bytes from a socket. Please read the "see
# 328 : : * also" section for more detail.
# 329 : : *
# 330 : : * @param data The buffer where the read bytes should be stored.
# 331 : : * @param len The number of bytes to read into the specified buffer.
# 332 : : * @param timeout The total timeout in milliseconds for this read.
# 333 : : * @param hSocket The socket (has to be in non-blocking mode) from which to read
# 334 : : * bytes.
# 335 : : *
# 336 : : * @returns An IntrRecvError indicating the resulting status of this read.
# 337 : : * IntrRecvError::OK only if all of the specified number of bytes were
# 338 : : * read.
# 339 : : *
# 340 : : * @see This function can be interrupted by calling InterruptSocks5(bool).
# 341 : : * Sockets can be made non-blocking with SetSocketNonBlocking(const
# 342 : : * SOCKET&, bool).
# 343 : : */
# 344 : : static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
# 345 : 39 : {
# 346 : 39 : int64_t curTime = GetTimeMillis();
# 347 : 39 : int64_t endTime = curTime + timeout;
# 348 : 39 : // Maximum time to wait for I/O readiness. It will take up until this time
# 349 : 39 : // (in millis) to break off in case of an interruption.
# 350 : 39 : const int64_t maxWait = 1000;
# 351 : 96 : while (len > 0 && curTime < endTime) {
# 352 : 57 : ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
# 353 : 57 : if (ret > 0) {
# 354 : 39 : len -= ret;
# 355 : 39 : data += ret;
# 356 : 39 : } else if (ret == 0) { // Unexpected disconnection
# 357 : 0 : return IntrRecvError::Disconnected;
# 358 : 18 : } else { // Other error or blocking
# 359 : 18 : int nErr = WSAGetLastError();
# 360 : 18 : if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
# 361 : 18 : if (!IsSelectableSocket(hSocket)) {
# 362 : 0 : return IntrRecvError::NetworkError;
# 363 : 0 : }
# 364 : 18 : // Only wait at most maxWait milliseconds at a time, unless
# 365 : 18 : // we're approaching the end of the specified total timeout
# 366 : 18 : int timeout_ms = std::min(endTime - curTime, maxWait);
# 367 : : #ifdef USE_POLL
# 368 : : struct pollfd pollfd = {};
# 369 : : pollfd.fd = hSocket;
# 370 : : pollfd.events = POLLIN;
# 371 : : int nRet = poll(&pollfd, 1, timeout_ms);
# 372 : : #else
# 373 : : struct timeval tval = MillisToTimeval(timeout_ms);
# 374 : 18 : fd_set fdset;
# 375 : 18 : FD_ZERO(&fdset);
# 376 : 18 : FD_SET(hSocket, &fdset);
# 377 : 18 : int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
# 378 : 18 : #endif
# 379 : 18 : if (nRet == SOCKET_ERROR) {
# 380 : 0 : return IntrRecvError::NetworkError;
# 381 : 0 : }
# 382 : 0 : } else {
# 383 : 0 : return IntrRecvError::NetworkError;
# 384 : 0 : }
# 385 : 57 : }
# 386 : 57 : if (interruptSocks5Recv)
# 387 : 0 : return IntrRecvError::Interrupted;
# 388 : 57 : curTime = GetTimeMillis();
# 389 : 57 : }
# 390 : 39 : return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
# 391 : 39 : }
# 392 : :
# 393 : : /** Credentials for proxy authentication */
# 394 : : struct ProxyCredentials
# 395 : : {
# 396 : : std::string username;
# 397 : : std::string password;
# 398 : : };
# 399 : :
# 400 : : /** Convert SOCKS5 reply to an error message */
# 401 : : static std::string Socks5ErrorString(uint8_t err)
# 402 : 0 : {
# 403 : 0 : switch(err) {
# 404 : 0 : case SOCKS5Reply::GENFAILURE:
# 405 : 0 : return "general failure";
# 406 : 0 : case SOCKS5Reply::NOTALLOWED:
# 407 : 0 : return "connection not allowed";
# 408 : 0 : case SOCKS5Reply::NETUNREACHABLE:
# 409 : 0 : return "network unreachable";
# 410 : 0 : case SOCKS5Reply::HOSTUNREACHABLE:
# 411 : 0 : return "host unreachable";
# 412 : 0 : case SOCKS5Reply::CONNREFUSED:
# 413 : 0 : return "connection refused";
# 414 : 0 : case SOCKS5Reply::TTLEXPIRED:
# 415 : 0 : return "TTL expired";
# 416 : 0 : case SOCKS5Reply::CMDUNSUPPORTED:
# 417 : 0 : return "protocol error";
# 418 : 0 : case SOCKS5Reply::ATYPEUNSUPPORTED:
# 419 : 0 : return "address type not supported";
# 420 : 0 : default:
# 421 : 0 : return "unknown";
# 422 : 0 : }
# 423 : 0 : }
# 424 : :
# 425 : : /**
# 426 : : * Connect to a specified destination service through an already connected
# 427 : : * SOCKS5 proxy.
# 428 : : *
# 429 : : * @param strDest The destination fully-qualified domain name.
# 430 : : * @param port The destination port.
# 431 : : * @param auth The credentials with which to authenticate with the specified
# 432 : : * SOCKS5 proxy.
# 433 : : * @param hSocket The SOCKS5 proxy socket.
# 434 : : *
# 435 : : * @returns Whether or not the operation succeeded.
# 436 : : *
# 437 : : * @note The specified SOCKS5 proxy socket must already be connected to the
# 438 : : * SOCKS5 proxy.
# 439 : : *
# 440 : : * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
# 441 : : * Version 5</a>
# 442 : : */
# 443 : : static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
# 444 : 9 : {
# 445 : 9 : IntrRecvError recvr;
# 446 : 9 : LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
# 447 : 9 : if (strDest.size() > 255) {
# 448 : 0 : return error("Hostname too long");
# 449 : 0 : }
# 450 : 9 : // Construct the version identifier/method selection message
# 451 : 9 : std::vector<uint8_t> vSocks5Init;
# 452 : 9 : vSocks5Init.push_back(SOCKSVersion::SOCKS5); // We want the SOCK5 protocol
# 453 : 9 : if (auth) {
# 454 : 6 : vSocks5Init.push_back(0x02); // 2 method identifiers follow...
# 455 : 6 : vSocks5Init.push_back(SOCKS5Method::NOAUTH);
# 456 : 6 : vSocks5Init.push_back(SOCKS5Method::USER_PASS);
# 457 : 6 : } else {
# 458 : 3 : vSocks5Init.push_back(0x01); // 1 method identifier follows...
# 459 : 3 : vSocks5Init.push_back(SOCKS5Method::NOAUTH);
# 460 : 3 : }
# 461 : 9 : ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
# 462 : 9 : if (ret != (ssize_t)vSocks5Init.size()) {
# 463 : 0 : return error("Error sending to proxy");
# 464 : 0 : }
# 465 : 9 : uint8_t pchRet1[2];
# 466 : 9 : if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
# 467 : 0 : LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
# 468 : 0 : return false;
# 469 : 0 : }
# 470 : 9 : if (pchRet1[0] != SOCKSVersion::SOCKS5) {
# 471 : 0 : return error("Proxy failed to initialize");
# 472 : 0 : }
# 473 : 9 : if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
# 474 : 3 : // Perform username/password authentication (as described in RFC1929)
# 475 : 3 : std::vector<uint8_t> vAuth;
# 476 : 3 : vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
# 477 : 3 : if (auth->username.size() > 255 || auth->password.size() > 255)
# 478 : 0 : return error("Proxy username or password too long");
# 479 : 3 : vAuth.push_back(auth->username.size());
# 480 : 3 : vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
# 481 : 3 : vAuth.push_back(auth->password.size());
# 482 : 3 : vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
# 483 : 3 : ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
# 484 : 3 : if (ret != (ssize_t)vAuth.size()) {
# 485 : 0 : return error("Error sending authentication to proxy");
# 486 : 0 : }
# 487 : 3 : LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
# 488 : 3 : uint8_t pchRetA[2];
# 489 : 3 : if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
# 490 : 0 : return error("Error reading proxy authentication response");
# 491 : 0 : }
# 492 : 3 : if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
# 493 : 0 : return error("Proxy authentication unsuccessful");
# 494 : 0 : }
# 495 : 6 : } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
# 496 : 6 : // Perform no authentication
# 497 : 6 : } else {
# 498 : 0 : return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
# 499 : 0 : }
# 500 : 9 : std::vector<uint8_t> vSocks5;
# 501 : 9 : vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
# 502 : 9 : vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
# 503 : 9 : vSocks5.push_back(0x00); // RSV Reserved must be 0
# 504 : 9 : vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
# 505 : 9 : vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
# 506 : 9 : vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
# 507 : 9 : vSocks5.push_back((port >> 8) & 0xFF);
# 508 : 9 : vSocks5.push_back((port >> 0) & 0xFF);
# 509 : 9 : ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
# 510 : 9 : if (ret != (ssize_t)vSocks5.size()) {
# 511 : 0 : return error("Error sending to proxy");
# 512 : 0 : }
# 513 : 9 : uint8_t pchRet2[4];
# 514 : 9 : if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
# 515 : 0 : if (recvr == IntrRecvError::Timeout) {
# 516 : 0 : /* If a timeout happens here, this effectively means we timed out while connecting
# 517 : 0 : * to the remote node. This is very common for Tor, so do not print an
# 518 : 0 : * error message. */
# 519 : 0 : return false;
# 520 : 0 : } else {
# 521 : 0 : return error("Error while reading proxy response");
# 522 : 0 : }
# 523 : 9 : }
# 524 : 9 : if (pchRet2[0] != SOCKSVersion::SOCKS5) {
# 525 : 0 : return error("Proxy failed to accept request");
# 526 : 0 : }
# 527 : 9 : if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
# 528 : 0 : // Failures to connect to a peer that are not proxy errors
# 529 : 0 : LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
# 530 : 0 : return false;
# 531 : 0 : }
# 532 : 9 : if (pchRet2[2] != 0x00) { // Reserved field must be 0
# 533 : 0 : return error("Error: malformed proxy response");
# 534 : 0 : }
# 535 : 9 : uint8_t pchRet3[256];
# 536 : 9 : switch (pchRet2[3])
# 537 : 9 : {
# 538 : 9 : case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
# 539 : 0 : case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
# 540 : 0 : case SOCKS5Atyp::DOMAINNAME:
# 541 : 0 : {
# 542 : 0 : recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
# 543 : 0 : if (recvr != IntrRecvError::OK) {
# 544 : 0 : return error("Error reading from proxy");
# 545 : 0 : }
# 546 : 0 : int nRecv = pchRet3[0];
# 547 : 0 : recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
# 548 : 0 : break;
# 549 : 0 : }
# 550 : 0 : default: return error("Error: malformed proxy response");
# 551 : 9 : }
# 552 : 9 : if (recvr != IntrRecvError::OK) {
# 553 : 0 : return error("Error reading from proxy");
# 554 : 0 : }
# 555 : 9 : if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
# 556 : 0 : return error("Error reading from proxy");
# 557 : 0 : }
# 558 : 9 : LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
# 559 : 9 : return true;
# 560 : 9 : }
# 561 : :
# 562 : : /**
# 563 : : * Try to create a socket file descriptor with specific properties in the
# 564 : : * communications domain (address family) of the specified service.
# 565 : : *
# 566 : : * For details on the desired properties, see the inline comments in the source
# 567 : : * code.
# 568 : : */
# 569 : : SOCKET CreateSocket(const CService &addrConnect)
# 570 : 743 : {
# 571 : 743 : // Create a sockaddr from the specified service.
# 572 : 743 : struct sockaddr_storage sockaddr;
# 573 : 743 : socklen_t len = sizeof(sockaddr);
# 574 : 743 : if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
# 575 : 0 : LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
# 576 : 0 : return INVALID_SOCKET;
# 577 : 0 : }
# 578 : 743 :
# 579 : 743 : // Create a TCP socket in the address family of the specified service.
# 580 : 743 : SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
# 581 : 743 : if (hSocket == INVALID_SOCKET)
# 582 : 743 : return INVALID_SOCKET;
# 583 : 743 :
# 584 : 743 : // Ensure that waiting for I/O on this socket won't result in undefined
# 585 : 743 : // behavior.
# 586 : 743 : if (!IsSelectableSocket(hSocket)) {
# 587 : 0 : CloseSocket(hSocket);
# 588 : 0 : LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
# 589 : 0 : return INVALID_SOCKET;
# 590 : 0 : }
# 591 : 743 :
# 592 : 743 : #ifdef SO_NOSIGPIPE
# 593 : 743 : int set = 1;
# 594 : 743 : // Set the no-sigpipe option on the socket for BSD systems, other UNIXes
# 595 : 743 : // should use the MSG_NOSIGNAL flag for every send.
# 596 : 743 : setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
# 597 : 743 : #endif
# 598 : 743 :
# 599 : 743 : // Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
# 600 : 743 : SetSocketNoDelay(hSocket);
# 601 : 743 :
# 602 : 743 : // Set the non-blocking option on the socket.
# 603 : 743 : if (!SetSocketNonBlocking(hSocket, true)) {
# 604 : 0 : CloseSocket(hSocket);
# 605 : 0 : LogPrintf("CreateSocket: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
# 606 : 0 : }
# 607 : 743 : return hSocket;
# 608 : 743 : }
# 609 : :
# 610 : : template<typename... Args>
# 611 : 0 : static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) {
# 612 : 0 : std::string error_message = tfm::format(fmt, args...);
# 613 : 0 : if (manual_connection) {
# 614 : 0 : LogPrintf("%s\n", error_message);
# 615 : 0 : } else {
# 616 : 0 : LogPrint(BCLog::NET, "%s\n", error_message);
# 617 : 0 : }
# 618 : 0 : }
# 619 : :
# 620 : : /**
# 621 : : * Try to connect to the specified service on the specified socket.
# 622 : : *
# 623 : : * @param addrConnect The service to which to connect.
# 624 : : * @param hSocket The socket on which to connect.
# 625 : : * @param nTimeout Wait this many milliseconds for the connection to be
# 626 : : * established.
# 627 : : * @param manual_connection Whether or not the connection was manually requested
# 628 : : * (e.g. through the addnode RPC)
# 629 : : *
# 630 : : * @returns Whether or not a connection was successfully made.
# 631 : : */
# 632 : : bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
# 633 : 248 : {
# 634 : 248 : // Create a sockaddr from the specified service.
# 635 : 248 : struct sockaddr_storage sockaddr;
# 636 : 248 : socklen_t len = sizeof(sockaddr);
# 637 : 248 : if (hSocket == INVALID_SOCKET) {
# 638 : 0 : LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
# 639 : 0 : return false;
# 640 : 0 : }
# 641 : 248 : if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
# 642 : 0 : LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
# 643 : 0 : return false;
# 644 : 0 : }
# 645 : 248 :
# 646 : 248 : // Connect to the addrConnect service on the hSocket socket.
# 647 : 248 : if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
# 648 : 248 : {
# 649 : 247 : int nErr = WSAGetLastError();
# 650 : 247 : // WSAEINVAL is here because some legacy version of winsock uses it
# 651 : 247 : if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
# 652 : 247 : {
# 653 : 247 : // Connection didn't actually fail, but is being established
# 654 : 247 : // asynchronously. Thus, use async I/O api (select/poll)
# 655 : 247 : // synchronously to check for successful connection with a timeout.
# 656 : : #ifdef USE_POLL
# 657 : : struct pollfd pollfd = {};
# 658 : : pollfd.fd = hSocket;
# 659 : : pollfd.events = POLLIN | POLLOUT;
# 660 : : int nRet = poll(&pollfd, 1, nTimeout);
# 661 : : #else
# 662 : : struct timeval timeout = MillisToTimeval(nTimeout);
# 663 : 247 : fd_set fdset;
# 664 : 247 : FD_ZERO(&fdset);
# 665 : 247 : FD_SET(hSocket, &fdset);
# 666 : 247 : int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
# 667 : 247 : #endif
# 668 : 247 : // Upon successful completion, both select and poll return the total
# 669 : 247 : // number of file descriptors that have been selected. A value of 0
# 670 : 247 : // indicates that the call timed out and no file descriptors have
# 671 : 247 : // been selected.
# 672 : 247 : if (nRet == 0)
# 673 : 3 : {
# 674 : 3 : LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
# 675 : 3 : return false;
# 676 : 3 : }
# 677 : 244 : if (nRet == SOCKET_ERROR)
# 678 : 244 : {
# 679 : 0 : LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
# 680 : 0 : return false;
# 681 : 0 : }
# 682 : 244 :
# 683 : 244 : // Even if the select/poll was successful, the connect might not
# 684 : 244 : // have been successful. The reason for this failure is hidden away
# 685 : 244 : // in the SO_ERROR for the socket in modern systems. We read it into
# 686 : 244 : // nRet here.
# 687 : 244 : socklen_t nRetSize = sizeof(nRet);
# 688 : 244 : if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
# 689 : 244 : {
# 690 : 0 : LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
# 691 : 0 : return false;
# 692 : 0 : }
# 693 : 244 : if (nRet != 0)
# 694 : 0 : {
# 695 : 0 : LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
# 696 : 0 : return false;
# 697 : 0 : }
# 698 : 0 : }
# 699 : : #ifdef WIN32
# 700 : : else if (WSAGetLastError() != WSAEISCONN)
# 701 : : #else
# 702 : : else
# 703 : 0 : #endif
# 704 : 0 : {
# 705 : 0 : LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
# 706 : 0 : return false;
# 707 : 0 : }
# 708 : 245 : }
# 709 : 245 : return true;
# 710 : 245 : }
# 711 : :
# 712 : 10 : bool SetProxy(enum Network net, const proxyType &addrProxy) {
# 713 : 10 : assert(net >= 0 && net < NET_MAX);
# 714 : 10 : if (!addrProxy.IsValid())
# 715 : 0 : return false;
# 716 : 10 : LOCK(g_proxyinfo_mutex);
# 717 : 10 : proxyInfo[net] = addrProxy;
# 718 : 10 : return true;
# 719 : 10 : }
# 720 : :
# 721 : 386 : bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
# 722 : 386 : assert(net >= 0 && net < NET_MAX);
# 723 : 386 : LOCK(g_proxyinfo_mutex);
# 724 : 386 : if (!proxyInfo[net].IsValid())
# 725 : 371 : return false;
# 726 : 15 : proxyInfoOut = proxyInfo[net];
# 727 : 15 : return true;
# 728 : 15 : }
# 729 : :
# 730 : : /**
# 731 : : * Set the name proxy to use for all connections to nodes specified by a
# 732 : : * hostname. After setting this proxy, connecting to a node specified by a
# 733 : : * hostname won't result in a local lookup of said hostname, rather, connect to
# 734 : : * the node by asking the name proxy for a proxy connection to the hostname,
# 735 : : * effectively delegating the hostname lookup to the specified proxy.
# 736 : : *
# 737 : : * This delegation increases privacy for those who set the name proxy as they no
# 738 : : * longer leak their external hostname queries to their DNS servers.
# 739 : : *
# 740 : : * @returns Whether or not the operation succeeded.
# 741 : : *
# 742 : : * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
# 743 : : * server in common use (most notably Tor) actually implements UDP
# 744 : : * support, and a DNS resolver is beyond the scope of this project.
# 745 : : */
# 746 : 3 : bool SetNameProxy(const proxyType &addrProxy) {
# 747 : 3 : if (!addrProxy.IsValid())
# 748 : 0 : return false;
# 749 : 3 : LOCK(g_proxyinfo_mutex);
# 750 : 3 : nameProxy = addrProxy;
# 751 : 3 : return true;
# 752 : 3 : }
# 753 : :
# 754 : 4 : bool GetNameProxy(proxyType &nameProxyOut) {
# 755 : 4 : LOCK(g_proxyinfo_mutex);
# 756 : 4 : if(!nameProxy.IsValid())
# 757 : 1 : return false;
# 758 : 3 : nameProxyOut = nameProxy;
# 759 : 3 : return true;
# 760 : 3 : }
# 761 : :
# 762 : 247 : bool HaveNameProxy() {
# 763 : 247 : LOCK(g_proxyinfo_mutex);
# 764 : 247 : return nameProxy.IsValid();
# 765 : 247 : }
# 766 : :
# 767 : 26 : bool IsProxy(const CNetAddr &addr) {
# 768 : 26 : LOCK(g_proxyinfo_mutex);
# 769 : 156 : for (int i = 0; i < NET_MAX; i++) {
# 770 : 130 : if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy))
# 771 : 0 : return true;
# 772 : 130 : }
# 773 : 26 : return false;
# 774 : 26 : }
# 775 : :
# 776 : : /**
# 777 : : * Connect to a specified destination service through a SOCKS5 proxy by first
# 778 : : * connecting to the SOCKS5 proxy.
# 779 : : *
# 780 : : * @param proxy The SOCKS5 proxy.
# 781 : : * @param strDest The destination service to which to connect.
# 782 : : * @param port The destination port.
# 783 : : * @param hSocket The socket on which to connect to the SOCKS5 proxy.
# 784 : : * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
# 785 : : * proxy to be established.
# 786 : : * @param[out] outProxyConnectionFailed Whether or not the connection to the
# 787 : : * SOCKS5 proxy failed.
# 788 : : *
# 789 : : * @returns Whether or not the operation succeeded.
# 790 : : */
# 791 : : bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool& outProxyConnectionFailed)
# 792 : 9 : {
# 793 : 9 : // first connect to proxy server
# 794 : 9 : if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
# 795 : 0 : outProxyConnectionFailed = true;
# 796 : 0 : return false;
# 797 : 0 : }
# 798 : 9 : // do socks negotiation
# 799 : 9 : if (proxy.randomize_credentials) {
# 800 : 6 : ProxyCredentials random_auth;
# 801 : 6 : static std::atomic_int counter(0);
# 802 : 6 : random_auth.username = random_auth.password = strprintf("%i", counter++);
# 803 : 6 : if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
# 804 : 0 : return false;
# 805 : 0 : }
# 806 : 3 : } else {
# 807 : 3 : if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
# 808 : 0 : return false;
# 809 : 0 : }
# 810 : 9 : }
# 811 : 9 : return true;
# 812 : 9 : }
# 813 : :
# 814 : : /**
# 815 : : * Parse and resolve a specified subnet string into the appropriate internal
# 816 : : * representation.
# 817 : : *
# 818 : : * @param strSubnet A string representation of a subnet of the form `network
# 819 : : * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
# 820 : : * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
# 821 : : * @param ret The resulting internal representation of a subnet.
# 822 : : *
# 823 : : * @returns Whether the operation succeeded or not.
# 824 : : */
# 825 : : bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
# 826 : 249 : {
# 827 : 249 : if (!ValidAsCString(strSubnet)) {
# 828 : 12 : return false;
# 829 : 12 : }
# 830 : 237 : size_t slash = strSubnet.find_last_of('/');
# 831 : 237 : std::vector<CNetAddr> vIP;
# 832 : 237 :
# 833 : 237 : std::string strAddress = strSubnet.substr(0, slash);
# 834 : 237 : // TODO: Use LookupHost(const std::string&, CNetAddr&, bool) instead to just get
# 835 : 237 : // one CNetAddr.
# 836 : 237 : if (LookupHost(strAddress, vIP, 1, false))
# 837 : 226 : {
# 838 : 226 : CNetAddr network = vIP[0];
# 839 : 226 : if (slash != strSubnet.npos)
# 840 : 158 : {
# 841 : 158 : std::string strNetmask = strSubnet.substr(slash + 1);
# 842 : 158 : uint32_t n;
# 843 : 158 : if (ParseUInt32(strNetmask, &n)) {
# 844 : 70 : if (n > std::numeric_limits<uint8_t>::max()) {
# 845 : 2 : return false;
# 846 : 2 : }
# 847 : 68 : // If valid number, assume CIDR variable-length subnet masking
# 848 : 68 : ret = CSubNet(network, (uint8_t)n);
# 849 : 68 : return ret.IsValid();
# 850 : 68 : }
# 851 : 88 : else // If not a valid number, try full netmask syntax
# 852 : 88 : {
# 853 : 88 : // Never allow lookup for netmask
# 854 : 88 : if (LookupHost(strNetmask, vIP, 1, false)) {
# 855 : 84 : ret = CSubNet(network, vIP[0]);
# 856 : 84 : return ret.IsValid();
# 857 : 84 : }
# 858 : 68 : }
# 859 : 68 : }
# 860 : 68 : else
# 861 : 68 : {
# 862 : 68 : ret = CSubNet(network);
# 863 : 68 : return ret.IsValid();
# 864 : 68 : }
# 865 : 15 : }
# 866 : 15 : return false;
# 867 : 15 : }
# 868 : :
# 869 : : #ifdef WIN32
# 870 : : std::string NetworkErrorString(int err)
# 871 : : {
# 872 : : wchar_t buf[256];
# 873 : : buf[0] = 0;
# 874 : : if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
# 875 : : nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
# 876 : : buf, ARRAYSIZE(buf), nullptr))
# 877 : : {
# 878 : : return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
# 879 : : }
# 880 : : else
# 881 : : {
# 882 : : return strprintf("Unknown error (%d)", err);
# 883 : : }
# 884 : : }
# 885 : : #else
# 886 : : std::string NetworkErrorString(int err)
# 887 : 10 : {
# 888 : 10 : char buf[256];
# 889 : 10 : buf[0] = 0;
# 890 : 10 : /* Too bad there are two incompatible implementations of the
# 891 : 10 : * thread-safe strerror. */
# 892 : 10 : const char *s;
# 893 : : #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
# 894 : : s = strerror_r(err, buf, sizeof(buf));
# 895 : : #else /* POSIX variant always returns message in buffer */
# 896 : : s = buf;
# 897 : 10 : if (strerror_r(err, buf, sizeof(buf)))
# 898 : 0 : buf[0] = 0;
# 899 : 10 : #endif
# 900 : 10 : return strprintf("%s (%d)", s, err);
# 901 : 10 : }
# 902 : : #endif
# 903 : :
# 904 : : bool CloseSocket(SOCKET& hSocket)
# 905 : 1928 : {
# 906 : 1928 : if (hSocket == INVALID_SOCKET)
# 907 : 1928 : return false;
# 908 : : #ifdef WIN32
# 909 : : int ret = closesocket(hSocket);
# 910 : : #else
# 911 : 1197 : int ret = close(hSocket);
# 912 : 1197 : #endif
# 913 : 1197 : if (ret) {
# 914 : 0 : LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError()));
# 915 : 0 : }
# 916 : 1197 : hSocket = INVALID_SOCKET;
# 917 : 1197 : return ret != SOCKET_ERROR;
# 918 : 1197 : }
# 919 : :
# 920 : : bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking)
# 921 : 743 : {
# 922 : 743 : if (fNonBlocking) {
# 923 : : #ifdef WIN32
# 924 : : u_long nOne = 1;
# 925 : : if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
# 926 : : #else
# 927 : : int fFlags = fcntl(hSocket, F_GETFL, 0);
# 928 : 743 : if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
# 929 : 0 : #endif
# 930 : 0 : return false;
# 931 : 0 : }
# 932 : 0 : } else {
# 933 : : #ifdef WIN32
# 934 : : u_long nZero = 0;
# 935 : : if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
# 936 : : #else
# 937 : : int fFlags = fcntl(hSocket, F_GETFL, 0);
# 938 : 0 : if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
# 939 : 0 : #endif
# 940 : 0 : return false;
# 941 : 0 : }
# 942 : 743 : }
# 943 : 743 :
# 944 : 743 : return true;
# 945 : 743 : }
# 946 : :
# 947 : : bool SetSocketNoDelay(const SOCKET& hSocket)
# 948 : 1197 : {
# 949 : 1197 : int set = 1;
# 950 : 1197 : int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
# 951 : 1197 : return rc == 0;
# 952 : 1197 : }
# 953 : :
# 954 : : void InterruptSocks5(bool interrupt)
# 955 : 1670 : {
# 956 : 1670 : interruptSocks5Recv = interrupt;
# 957 : 1670 : }
|