/Users/eugenesiegel/btc/bitcoin/src/netbase.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-2010 Satoshi Nakamoto | 
| 2 |  | // Copyright (c) 2009-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep | 
| 7 |  |  | 
| 8 |  | #include <netbase.h> | 
| 9 |  |  | 
| 10 |  | #include <compat/compat.h> | 
| 11 |  | #include <logging.h> | 
| 12 |  | #include <sync.h> | 
| 13 |  | #include <tinyformat.h> | 
| 14 |  | #include <util/sock.h> | 
| 15 |  | #include <util/strencodings.h> | 
| 16 |  | #include <util/string.h> | 
| 17 |  | #include <util/time.h> | 
| 18 |  |  | 
| 19 |  | #include <atomic> | 
| 20 |  | #include <chrono> | 
| 21 |  | #include <cstdint> | 
| 22 |  | #include <functional> | 
| 23 |  | #include <limits> | 
| 24 |  | #include <memory> | 
| 25 |  |  | 
| 26 |  | #ifdef HAVE_SOCKADDR_UN | 
| 27 |  | #include <sys/un.h> | 
| 28 |  | #endif | 
| 29 |  |  | 
| 30 |  | using util::ContainsNoNUL; | 
| 31 |  |  | 
| 32 |  | // Settings | 
| 33 |  | static GlobalMutex g_proxyinfo_mutex; | 
| 34 |  | static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex); | 
| 35 |  | static Proxy 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 | 
| 40 |  | std::chrono::milliseconds g_socks5_recv_timeout = 20s; | 
| 41 |  | CThreadInterrupt g_socks5_interrupt; | 
| 42 |  |  | 
| 43 |  | ReachableNets g_reachable_nets; | 
| 44 |  |  | 
| 45 |  | std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup) | 
| 46 | 0 | { | 
| 47 | 0 |     addrinfo ai_hint{}; | 
| 48 |  |     // We want a TCP port, which is a streaming socket type | 
| 49 | 0 |     ai_hint.ai_socktype = SOCK_STREAM; | 
| 50 | 0 |     ai_hint.ai_protocol = IPPROTO_TCP; | 
| 51 |  |     // We don't care which address family (IPv4 or IPv6) is returned | 
| 52 | 0 |     ai_hint.ai_family = AF_UNSPEC; | 
| 53 |  |  | 
| 54 |  |     // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only | 
| 55 |  |     // return addresses whose family we have an address configured for. | 
| 56 |  |     // | 
| 57 |  |     // If we don't allow lookups, then use the AI_NUMERICHOST flag for | 
| 58 |  |     // getaddrinfo to only decode numerical network addresses and suppress | 
| 59 |  |     // hostname lookups. | 
| 60 | 0 |     ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST; | 
| 61 |  | 
 | 
| 62 | 0 |     addrinfo* ai_res{nullptr}; | 
| 63 | 0 |     const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; | 
| 64 | 0 |     if (n_err != 0) { | 
| 65 | 0 |         if ((ai_hint.ai_flags & AI_ADDRCONFIG) == AI_ADDRCONFIG) { | 
| 66 |  |             // AI_ADDRCONFIG on some systems may exclude loopback-only addresses | 
| 67 |  |             // If first lookup failed we perform a second lookup without AI_ADDRCONFIG | 
| 68 | 0 |             ai_hint.ai_flags = (ai_hint.ai_flags & ~AI_ADDRCONFIG); | 
| 69 | 0 |             const int n_err_retry{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; | 
| 70 | 0 |             if (n_err_retry != 0) { | 
| 71 | 0 |                 return {}; | 
| 72 | 0 |             } | 
| 73 | 0 |         } else { | 
| 74 | 0 |             return {}; | 
| 75 | 0 |         } | 
| 76 | 0 |     } | 
| 77 |  |  | 
| 78 |  |     // Traverse the linked list starting with ai_trav. | 
| 79 | 0 |     addrinfo* ai_trav{ai_res}; | 
| 80 | 0 |     std::vector<CNetAddr> resolved_addresses; | 
| 81 | 0 |     while (ai_trav != nullptr) { | 
| 82 | 0 |         if (ai_trav->ai_family == AF_INET) { | 
| 83 | 0 |             assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in)); | 
| 84 | 0 |             resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr); | 
| 85 | 0 |         } | 
| 86 | 0 |         if (ai_trav->ai_family == AF_INET6) { | 
| 87 | 0 |             assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6)); | 
| 88 | 0 |             const sockaddr_in6* s6{reinterpret_cast<sockaddr_in6*>(ai_trav->ai_addr)}; | 
| 89 | 0 |             resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id); | 
| 90 | 0 |         } | 
| 91 | 0 |         ai_trav = ai_trav->ai_next; | 
| 92 | 0 |     } | 
| 93 | 0 |     freeaddrinfo(ai_res); | 
| 94 |  | 
 | 
| 95 | 0 |     return resolved_addresses; | 
| 96 | 0 | } | 
| 97 |  |  | 
| 98 |  | DNSLookupFn g_dns_lookup{WrappedGetAddrInfo}; | 
| 99 |  |  | 
| 100 | 0 | enum Network ParseNetwork(const std::string& net_in) { | 
| 101 | 0 |     std::string net = ToLower(net_in); | 
| 102 | 0 |     if (net == "ipv4") return NET_IPV4; | 
| 103 | 0 |     if (net == "ipv6") return NET_IPV6; | 
| 104 | 0 |     if (net == "onion") return NET_ONION; | 
| 105 | 0 |     if (net == "tor") { | 
| 106 | 0 |         LogPrintf("Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 107 | 0 |         return NET_ONION; | 
| 108 | 0 |     } | 
| 109 | 0 |     if (net == "i2p") { | 
| 110 | 0 |         return NET_I2P; | 
| 111 | 0 |     } | 
| 112 | 0 |     if (net == "cjdns") { | 
| 113 | 0 |         return NET_CJDNS; | 
| 114 | 0 |     } | 
| 115 | 0 |     return NET_UNROUTABLE; | 
| 116 | 0 | } | 
| 117 |  |  | 
| 118 |  | std::string GetNetworkName(enum Network net) | 
| 119 | 256k | { | 
| 120 | 256k |     switch (net) { | 
| 121 | 0 |     case NET_UNROUTABLE: return "not_publicly_routable"; | 
| 122 | 51.2k |     case NET_IPV4: return "ipv4"; | 
| 123 | 51.2k |     case NET_IPV6: return "ipv6"; | 
| 124 | 51.2k |     case NET_ONION: return "onion"; | 
| 125 | 51.2k |     case NET_I2P: return "i2p"; | 
| 126 | 51.2k |     case NET_CJDNS: return "cjdns"; | 
| 127 | 0 |     case NET_INTERNAL: return "internal"; | 
| 128 | 0 |     case NET_MAX: assert(false); | 
| 129 | 256k |     } // no default case, so the compiler can warn about missing cases | 
| 130 |  |  | 
| 131 | 0 |     assert(false); | 
| 132 | 0 | } | 
| 133 |  |  | 
| 134 |  | std::vector<std::string> GetNetworkNames(bool append_unroutable) | 
| 135 | 51.2k | { | 
| 136 | 51.2k |     std::vector<std::string> names; | 
| 137 | 410k |     for (int n = 0; n < NET_MAX; ++n358k) { | 
| 138 | 358k |         const enum Network network{static_cast<Network>(n)}; | 
| 139 | 358k |         if (network == NET_UNROUTABLE || network == NET_INTERNAL307k) continue102k; | 
| 140 | 256k |         names.emplace_back(GetNetworkName(network)); | 
| 141 | 256k |     } | 
| 142 | 51.2k |     if (append_unroutable) { | 
| 143 | 0 |         names.emplace_back(GetNetworkName(NET_UNROUTABLE)); | 
| 144 | 0 |     } | 
| 145 | 51.2k |     return names; | 
| 146 | 51.2k | } | 
| 147 |  |  | 
| 148 |  | static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function) | 
| 149 | 0 | { | 
| 150 | 0 |     if (!ContainsNoNUL(name)) return {}; | 
| 151 | 0 |     { | 
| 152 | 0 |         CNetAddr addr; | 
| 153 |  |         // From our perspective, onion addresses are not hostnames but rather | 
| 154 |  |         // direct encodings of CNetAddr much like IPv4 dotted-decimal notation | 
| 155 |  |         // or IPv6 colon-separated hextet notation. Since we can't use | 
| 156 |  |         // getaddrinfo to decode them and it wouldn't make sense to resolve | 
| 157 |  |         // them, we return a network address representing it instead. See | 
| 158 |  |         // CNetAddr::SetSpecial(const std::string&) for more details. | 
| 159 | 0 |         if (addr.SetSpecial(name)) return {addr}; | 
| 160 | 0 |     } | 
| 161 |  |  | 
| 162 | 0 |     std::vector<CNetAddr> addresses; | 
| 163 |  | 
 | 
| 164 | 0 |     for (const CNetAddr& resolved : dns_lookup_function(name, fAllowLookup)) { | 
| 165 | 0 |         if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) { | 
| 166 | 0 |             break; | 
| 167 | 0 |         } | 
| 168 |  |         /* Never allow resolving to an internal address. Consider any such result invalid */ | 
| 169 | 0 |         if (!resolved.IsInternal()) { | 
| 170 | 0 |             addresses.push_back(resolved); | 
| 171 | 0 |         } | 
| 172 | 0 |     } | 
| 173 |  | 
 | 
| 174 | 0 |     return addresses; | 
| 175 | 0 | } | 
| 176 |  |  | 
| 177 |  | std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function) | 
| 178 | 0 | { | 
| 179 | 0 |     if (!ContainsNoNUL(name)) return {}; | 
| 180 | 0 |     std::string strHost = name; | 
| 181 | 0 |     if (strHost.empty()) return {}; | 
| 182 | 0 |     if (strHost.front() == '[' && strHost.back() == ']') { | 
| 183 | 0 |         strHost = strHost.substr(1, strHost.size() - 2); | 
| 184 | 0 |     } | 
| 185 |  | 
 | 
| 186 | 0 |     return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function); | 
| 187 | 0 | } | 
| 188 |  |  | 
| 189 |  | std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function) | 
| 190 | 0 | { | 
| 191 | 0 |     const std::vector<CNetAddr> addresses{LookupHost(name, 1, fAllowLookup, dns_lookup_function)}; | 
| 192 | 0 |     return addresses.empty() ? std::nullopt : std::make_optional(addresses.front()); | 
| 193 | 0 | } | 
| 194 |  |  | 
| 195 |  | std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function) | 
| 196 | 0 | { | 
| 197 | 0 |     if (name.empty() || !ContainsNoNUL(name)) { | 
| 198 | 0 |         return {}; | 
| 199 | 0 |     } | 
| 200 | 0 |     uint16_t port{portDefault}; | 
| 201 | 0 |     std::string hostname; | 
| 202 | 0 |     SplitHostPort(name, port, hostname); | 
| 203 |  | 
 | 
| 204 | 0 |     const std::vector<CNetAddr> addresses{LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)}; | 
| 205 | 0 |     if (addresses.empty()) return {}; | 
| 206 | 0 |     std::vector<CService> services; | 
| 207 | 0 |     services.reserve(addresses.size()); | 
| 208 | 0 |     for (const auto& addr : addresses) | 
| 209 | 0 |         services.emplace_back(addr, port); | 
| 210 | 0 |     return services; | 
| 211 | 0 | } | 
| 212 |  |  | 
| 213 |  | std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function) | 
| 214 | 0 | { | 
| 215 | 0 |     const std::vector<CService> services{Lookup(name, portDefault, fAllowLookup, 1, dns_lookup_function)}; | 
| 216 |  | 
 | 
| 217 | 0 |     return services.empty() ? std::nullopt : std::make_optional(services.front()); | 
| 218 | 0 | } | 
| 219 |  |  | 
| 220 |  | CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function) | 
| 221 | 0 | { | 
| 222 | 0 |     if (!ContainsNoNUL(name)) { | 
| 223 | 0 |         return {}; | 
| 224 | 0 |     } | 
| 225 |  |     // "1.2:345" will fail to resolve the ip, but will still set the port. | 
| 226 |  |     // If the ip fails to resolve, re-init the result. | 
| 227 | 0 |     return Lookup(name, portDefault, /*fAllowLookup=*/false, dns_lookup_function).value_or(CService{}); | 
| 228 | 0 | } | 
| 229 |  |  | 
| 230 |  | bool IsUnixSocketPath(const std::string& name) | 
| 231 | 0 | { | 
| 232 | 0 | #ifdef HAVE_SOCKADDR_UN | 
| 233 | 0 |     if (!name.starts_with(ADDR_PREFIX_UNIX)) return false; | 
| 234 |  |  | 
| 235 |  |     // Split off "unix:" prefix | 
| 236 | 0 |     std::string str{name.substr(ADDR_PREFIX_UNIX.length())}; | 
| 237 |  |  | 
| 238 |  |     // Path size limit is platform-dependent | 
| 239 |  |     // see https://manpages.ubuntu.com/manpages/xenial/en/man7/unix.7.html | 
| 240 | 0 |     if (str.size() + 1 > sizeof(((sockaddr_un*)nullptr)->sun_path)) return false; | 
| 241 |  |  | 
| 242 | 0 |     return true; | 
| 243 |  | #else | 
| 244 |  |     return false; | 
| 245 |  | #endif | 
| 246 | 0 | } | 
| 247 |  |  | 
| 248 |  | /** SOCKS version */ | 
| 249 |  | enum SOCKSVersion: uint8_t { | 
| 250 |  |     SOCKS4 = 0x04, | 
| 251 |  |     SOCKS5 = 0x05 | 
| 252 |  | }; | 
| 253 |  |  | 
| 254 |  | /** Values defined for METHOD in RFC1928 */ | 
| 255 |  | enum SOCKS5Method: uint8_t { | 
| 256 |  |     NOAUTH = 0x00,        //!< No authentication required | 
| 257 |  |     GSSAPI = 0x01,        //!< GSSAPI | 
| 258 |  |     USER_PASS = 0x02,     //!< Username/password | 
| 259 |  |     NO_ACCEPTABLE = 0xff, //!< No acceptable methods | 
| 260 |  | }; | 
| 261 |  |  | 
| 262 |  | /** Values defined for CMD in RFC1928 */ | 
| 263 |  | enum SOCKS5Command: uint8_t { | 
| 264 |  |     CONNECT = 0x01, | 
| 265 |  |     BIND = 0x02, | 
| 266 |  |     UDP_ASSOCIATE = 0x03 | 
| 267 |  | }; | 
| 268 |  |  | 
| 269 |  | /** Values defined for REP in RFC1928 and https://spec.torproject.org/socks-extensions.html */ | 
| 270 |  | enum SOCKS5Reply: uint8_t { | 
| 271 |  |     SUCCEEDED = 0x00,                  //!< RFC1928: Succeeded | 
| 272 |  |     GENFAILURE = 0x01,                 //!< RFC1928: General failure | 
| 273 |  |     NOTALLOWED = 0x02,                 //!< RFC1928: Connection not allowed by ruleset | 
| 274 |  |     NETUNREACHABLE = 0x03,             //!< RFC1928: Network unreachable | 
| 275 |  |     HOSTUNREACHABLE = 0x04,            //!< RFC1928: Network unreachable | 
| 276 |  |     CONNREFUSED = 0x05,                //!< RFC1928: Connection refused | 
| 277 |  |     TTLEXPIRED = 0x06,                 //!< RFC1928: TTL expired | 
| 278 |  |     CMDUNSUPPORTED = 0x07,             //!< RFC1928: Command not supported | 
| 279 |  |     ATYPEUNSUPPORTED = 0x08,           //!< RFC1928: Address type not supported | 
| 280 |  |     TOR_HS_DESC_NOT_FOUND = 0xf0,      //!< Tor: Onion service descriptor can not be found | 
| 281 |  |     TOR_HS_DESC_INVALID = 0xf1,        //!< Tor: Onion service descriptor is invalid | 
| 282 |  |     TOR_HS_INTRO_FAILED = 0xf2,        //!< Tor: Onion service introduction failed | 
| 283 |  |     TOR_HS_REND_FAILED = 0xf3,         //!< Tor: Onion service rendezvous failed | 
| 284 |  |     TOR_HS_MISSING_CLIENT_AUTH = 0xf4, //!< Tor: Onion service missing client authorization | 
| 285 |  |     TOR_HS_WRONG_CLIENT_AUTH = 0xf5,   //!< Tor: Onion service wrong client authorization | 
| 286 |  |     TOR_HS_BAD_ADDRESS = 0xf6,         //!< Tor: Onion service invalid address | 
| 287 |  |     TOR_HS_INTRO_TIMEOUT = 0xf7,       //!< Tor: Onion service introduction timed out | 
| 288 |  | }; | 
| 289 |  |  | 
| 290 |  | /** Values defined for ATYPE in RFC1928 */ | 
| 291 |  | enum SOCKS5Atyp: uint8_t { | 
| 292 |  |     IPV4 = 0x01, | 
| 293 |  |     DOMAINNAME = 0x03, | 
| 294 |  |     IPV6 = 0x04, | 
| 295 |  | }; | 
| 296 |  |  | 
| 297 |  | /** Status codes that can be returned by InterruptibleRecv */ | 
| 298 |  | enum class IntrRecvError { | 
| 299 |  |     OK, | 
| 300 |  |     Timeout, | 
| 301 |  |     Disconnected, | 
| 302 |  |     NetworkError, | 
| 303 |  |     Interrupted | 
| 304 |  | }; | 
| 305 |  |  | 
| 306 |  | /** | 
| 307 |  |  * Try to read a specified number of bytes from a socket. Please read the "see | 
| 308 |  |  * also" section for more detail. | 
| 309 |  |  * | 
| 310 |  |  * @param data The buffer where the read bytes should be stored. | 
| 311 |  |  * @param len The number of bytes to read into the specified buffer. | 
| 312 |  |  * @param timeout The total timeout for this read. | 
| 313 |  |  * @param sock The socket (has to be in non-blocking mode) from which to read bytes. | 
| 314 |  |  * | 
| 315 |  |  * @returns An IntrRecvError indicating the resulting status of this read. | 
| 316 |  |  *          IntrRecvError::OK only if all of the specified number of bytes were | 
| 317 |  |  *          read. | 
| 318 |  |  * | 
| 319 |  |  * @see This function can be interrupted by calling g_socks5_interrupt(). | 
| 320 |  |  *      Sockets can be made non-blocking with Sock::SetNonBlocking(). | 
| 321 |  |  */ | 
| 322 |  | static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::milliseconds timeout, const Sock& sock) | 
| 323 | 0 | { | 
| 324 | 0 |     auto curTime{Now<SteadyMilliseconds>()}; | 
| 325 | 0 |     const auto endTime{curTime + timeout}; | 
| 326 | 0 |     while (len > 0 && curTime < endTime) { | 
| 327 | 0 |         ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first | 
| 328 | 0 |         if (ret > 0) { | 
| 329 | 0 |             len -= ret; | 
| 330 | 0 |             data += ret; | 
| 331 | 0 |         } else if (ret == 0) { // Unexpected disconnection | 
| 332 | 0 |             return IntrRecvError::Disconnected; | 
| 333 | 0 |         } else { // Other error or blocking | 
| 334 | 0 |             int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 335 | 0 |             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {| Line | Count | Source |  | 53 | 0 | #define WSAEINPROGRESS      EINPROGRESS | 
 |             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {| Line | Count | Source |  | 49 | 0 | #define WSAEWOULDBLOCK      EWOULDBLOCK | 
 |             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {| Line | Count | Source |  | 48 | 0 | #define WSAEINVAL           EINVAL | 
 | 
| 336 |  |                 // Only wait at most MAX_WAIT_FOR_IO at a time, unless | 
| 337 |  |                 // we're approaching the end of the specified total timeout | 
| 338 | 0 |                 const auto remaining = std::chrono::milliseconds{endTime - curTime}; | 
| 339 | 0 |                 const auto timeout = std::min(remaining, std::chrono::milliseconds{MAX_WAIT_FOR_IO}); | 
| 340 | 0 |                 if (!sock.Wait(timeout, Sock::RECV)) { | 
| 341 | 0 |                     return IntrRecvError::NetworkError; | 
| 342 | 0 |                 } | 
| 343 | 0 |             } else { | 
| 344 | 0 |                 return IntrRecvError::NetworkError; | 
| 345 | 0 |             } | 
| 346 | 0 |         } | 
| 347 | 0 |         if (g_socks5_interrupt) { | 
| 348 | 0 |             return IntrRecvError::Interrupted; | 
| 349 | 0 |         } | 
| 350 | 0 |         curTime = Now<SteadyMilliseconds>(); | 
| 351 | 0 |     } | 
| 352 | 0 |     return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; | 
| 353 | 0 | } | 
| 354 |  |  | 
| 355 |  | /** Convert SOCKS5 reply to an error message */ | 
| 356 |  | static std::string Socks5ErrorString(uint8_t err) | 
| 357 | 0 | { | 
| 358 | 0 |     switch(err) { | 
| 359 | 0 |         case SOCKS5Reply::GENFAILURE: | 
| 360 | 0 |             return "general failure"; | 
| 361 | 0 |         case SOCKS5Reply::NOTALLOWED: | 
| 362 | 0 |             return "connection not allowed"; | 
| 363 | 0 |         case SOCKS5Reply::NETUNREACHABLE: | 
| 364 | 0 |             return "network unreachable"; | 
| 365 | 0 |         case SOCKS5Reply::HOSTUNREACHABLE: | 
| 366 | 0 |             return "host unreachable"; | 
| 367 | 0 |         case SOCKS5Reply::CONNREFUSED: | 
| 368 | 0 |             return "connection refused"; | 
| 369 | 0 |         case SOCKS5Reply::TTLEXPIRED: | 
| 370 | 0 |             return "TTL expired"; | 
| 371 | 0 |         case SOCKS5Reply::CMDUNSUPPORTED: | 
| 372 | 0 |             return "protocol error"; | 
| 373 | 0 |         case SOCKS5Reply::ATYPEUNSUPPORTED: | 
| 374 | 0 |             return "address type not supported"; | 
| 375 | 0 |         case SOCKS5Reply::TOR_HS_DESC_NOT_FOUND: | 
| 376 | 0 |             return "onion service descriptor can not be found"; | 
| 377 | 0 |         case SOCKS5Reply::TOR_HS_DESC_INVALID: | 
| 378 | 0 |             return "onion service descriptor is invalid"; | 
| 379 | 0 |         case SOCKS5Reply::TOR_HS_INTRO_FAILED: | 
| 380 | 0 |             return "onion service introduction failed"; | 
| 381 | 0 |         case SOCKS5Reply::TOR_HS_REND_FAILED: | 
| 382 | 0 |             return "onion service rendezvous failed"; | 
| 383 | 0 |         case SOCKS5Reply::TOR_HS_MISSING_CLIENT_AUTH: | 
| 384 | 0 |             return "onion service missing client authorization"; | 
| 385 | 0 |         case SOCKS5Reply::TOR_HS_WRONG_CLIENT_AUTH: | 
| 386 | 0 |             return "onion service wrong client authorization"; | 
| 387 | 0 |         case SOCKS5Reply::TOR_HS_BAD_ADDRESS: | 
| 388 | 0 |             return "onion service invalid address"; | 
| 389 | 0 |         case SOCKS5Reply::TOR_HS_INTRO_TIMEOUT: | 
| 390 | 0 |             return "onion service introduction timed out"; | 
| 391 | 0 |         default: | 
| 392 | 0 |             return strprintf("unknown (0x%02x)", err);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 393 | 0 |     } | 
| 394 | 0 | } | 
| 395 |  |  | 
| 396 |  | bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& sock) | 
| 397 | 0 | { | 
| 398 | 0 |     try { | 
| 399 | 0 |         IntrRecvError recvr; | 
| 400 | 0 |         LogDebug(BCLog::NET, "SOCKS5 connecting %s\n", strDest); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 401 | 0 |         if (strDest.size() > 255) { | 
| 402 | 0 |             LogError("Hostname too long\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 403 | 0 |             return false; | 
| 404 | 0 |         } | 
| 405 |  |         // Construct the version identifier/method selection message | 
| 406 | 0 |         std::vector<uint8_t> vSocks5Init; | 
| 407 | 0 |         vSocks5Init.push_back(SOCKSVersion::SOCKS5); // We want the SOCK5 protocol | 
| 408 | 0 |         if (auth) { | 
| 409 | 0 |             vSocks5Init.push_back(0x02); // 2 method identifiers follow... | 
| 410 | 0 |             vSocks5Init.push_back(SOCKS5Method::NOAUTH); | 
| 411 | 0 |             vSocks5Init.push_back(SOCKS5Method::USER_PASS); | 
| 412 | 0 |         } else { | 
| 413 | 0 |             vSocks5Init.push_back(0x01); // 1 method identifier follows... | 
| 414 | 0 |             vSocks5Init.push_back(SOCKS5Method::NOAUTH); | 
| 415 | 0 |         } | 
| 416 | 0 |         sock.SendComplete(vSocks5Init, g_socks5_recv_timeout, g_socks5_interrupt); | 
| 417 | 0 |         uint8_t pchRet1[2]; | 
| 418 | 0 |         if (InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { | 
| 419 | 0 |             LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 420 | 0 |             return false; | 
| 421 | 0 |         } | 
| 422 | 0 |         if (pchRet1[0] != SOCKSVersion::SOCKS5) { | 
| 423 | 0 |             LogError("Proxy failed to initialize\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 424 | 0 |             return false; | 
| 425 | 0 |         } | 
| 426 | 0 |         if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) { | 
| 427 |  |             // Perform username/password authentication (as described in RFC1929) | 
| 428 | 0 |             std::vector<uint8_t> vAuth; | 
| 429 | 0 |             vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation | 
| 430 | 0 |             if (auth->username.size() > 255 || auth->password.size() > 255) { | 
| 431 | 0 |                 LogError("Proxy username or password too long\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 432 | 0 |                 return false; | 
| 433 | 0 |             } | 
| 434 | 0 |             vAuth.push_back(auth->username.size()); | 
| 435 | 0 |             vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); | 
| 436 | 0 |             vAuth.push_back(auth->password.size()); | 
| 437 | 0 |             vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); | 
| 438 | 0 |             sock.SendComplete(vAuth, g_socks5_recv_timeout, g_socks5_interrupt); | 
| 439 | 0 |             LogDebug(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 440 | 0 |             uint8_t pchRetA[2]; | 
| 441 | 0 |             if (InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { | 
| 442 | 0 |                 LogError("Error reading proxy authentication response\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 443 | 0 |                 return false; | 
| 444 | 0 |             } | 
| 445 | 0 |             if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { | 
| 446 | 0 |                 LogError("Proxy authentication unsuccessful\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 447 | 0 |                 return false; | 
| 448 | 0 |             } | 
| 449 | 0 |         } else if (pchRet1[1] == SOCKS5Method::NOAUTH) { | 
| 450 |  |             // Perform no authentication | 
| 451 | 0 |         } else { | 
| 452 | 0 |             LogError("Proxy requested wrong authentication method %02x\n", pchRet1[1]);| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 453 | 0 |             return false; | 
| 454 | 0 |         } | 
| 455 | 0 |         std::vector<uint8_t> vSocks5; | 
| 456 | 0 |         vSocks5.push_back(SOCKSVersion::SOCKS5);   // VER protocol version | 
| 457 | 0 |         vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT | 
| 458 | 0 |         vSocks5.push_back(0x00);                   // RSV Reserved must be 0 | 
| 459 | 0 |         vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME | 
| 460 | 0 |         vSocks5.push_back(strDest.size());         // Length<=255 is checked at beginning of function | 
| 461 | 0 |         vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); | 
| 462 | 0 |         vSocks5.push_back((port >> 8) & 0xFF); | 
| 463 | 0 |         vSocks5.push_back((port >> 0) & 0xFF); | 
| 464 | 0 |         sock.SendComplete(vSocks5, g_socks5_recv_timeout, g_socks5_interrupt); | 
| 465 | 0 |         uint8_t pchRet2[4]; | 
| 466 | 0 |         if ((recvr = InterruptibleRecv(pchRet2, 4, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { | 
| 467 | 0 |             if (recvr == IntrRecvError::Timeout) { | 
| 468 |  |                 /* If a timeout happens here, this effectively means we timed out while connecting | 
| 469 |  |                  * to the remote node. This is very common for Tor, so do not print an | 
| 470 |  |                  * error message. */ | 
| 471 | 0 |                 return false; | 
| 472 | 0 |             } else { | 
| 473 | 0 |                 LogError("Error while reading proxy response\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 474 | 0 |                 return false; | 
| 475 | 0 |             } | 
| 476 | 0 |         } | 
| 477 | 0 |         if (pchRet2[0] != SOCKSVersion::SOCKS5) { | 
| 478 | 0 |             LogError("Proxy failed to accept request\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 479 | 0 |             return false; | 
| 480 | 0 |         } | 
| 481 | 0 |         if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) { | 
| 482 |  |             // Failures to connect to a peer that are not proxy errors | 
| 483 | 0 |             LogPrintLevel(BCLog::NET, BCLog::Level::Debug, | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 484 | 0 |                           "Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1])); | 
| 485 | 0 |             return false; | 
| 486 | 0 |         } | 
| 487 | 0 |         if (pchRet2[2] != 0x00) { // Reserved field must be 0 | 
| 488 | 0 |             LogError("Error: malformed proxy response\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 489 | 0 |             return false; | 
| 490 | 0 |         } | 
| 491 | 0 |         uint8_t pchRet3[256]; | 
| 492 | 0 |         switch (pchRet2[3]) { | 
| 493 | 0 |         case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, g_socks5_recv_timeout, sock); break; | 
| 494 | 0 |         case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, g_socks5_recv_timeout, sock); break; | 
| 495 | 0 |         case SOCKS5Atyp::DOMAINNAME: { | 
| 496 | 0 |             recvr = InterruptibleRecv(pchRet3, 1, g_socks5_recv_timeout, sock); | 
| 497 | 0 |             if (recvr != IntrRecvError::OK) { | 
| 498 | 0 |                 LogError("Error reading from proxy\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 499 | 0 |                 return false; | 
| 500 | 0 |             } | 
| 501 | 0 |             int nRecv = pchRet3[0]; | 
| 502 | 0 |             recvr = InterruptibleRecv(pchRet3, nRecv, g_socks5_recv_timeout, sock); | 
| 503 | 0 |             break; | 
| 504 | 0 |         } | 
| 505 | 0 |         default: { | 
| 506 | 0 |             LogError("Error: malformed proxy response\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 507 | 0 |             return false; | 
| 508 | 0 |         } | 
| 509 | 0 |         } | 
| 510 | 0 |         if (recvr != IntrRecvError::OK) { | 
| 511 | 0 |             LogError("Error reading from proxy\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 512 | 0 |             return false; | 
| 513 | 0 |         } | 
| 514 | 0 |         if (InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) { | 
| 515 | 0 |             LogError("Error reading from proxy\n");| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 516 | 0 |             return false; | 
| 517 | 0 |         } | 
| 518 | 0 |         LogDebug(BCLog::NET, "SOCKS5 connected %s\n", strDest); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 519 | 0 |         return true; | 
| 520 | 0 |     } catch (const std::runtime_error& e) { | 
| 521 | 0 |         LogError("Error during SOCKS5 proxy handshake: %s\n", e.what());| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 522 | 0 |         return false; | 
| 523 | 0 |     } | 
| 524 | 0 | } | 
| 525 |  |  | 
| 526 |  | std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol) | 
| 527 | 0 | { | 
| 528 |  |     // Not IPv4, IPv6 or UNIX | 
| 529 | 0 |     if (domain == AF_UNSPEC) return nullptr; | 
| 530 |  |  | 
| 531 |  |     // Create a socket in the specified address family. | 
| 532 | 0 |     SOCKET hSocket = socket(domain, type, protocol); | 
| 533 | 0 |     if (hSocket == INVALID_SOCKET) {| Line | Count | Source |  | 55 | 0 | #define INVALID_SOCKET      (SOCKET)(~0) | 
 | 
| 534 | 0 |         return nullptr; | 
| 535 | 0 |     } | 
| 536 |  |  | 
| 537 | 0 |     auto sock = std::make_unique<Sock>(hSocket); | 
| 538 |  | 
 | 
| 539 | 0 |     if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNIX) { | 
| 540 | 0 |         return sock; | 
| 541 | 0 |     } | 
| 542 |  |  | 
| 543 |  |     // Ensure that waiting for I/O on this socket won't result in undefined | 
| 544 |  |     // behavior. | 
| 545 | 0 |     if (!sock->IsSelectable()) { | 
| 546 | 0 |         LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 547 | 0 |         return nullptr; | 
| 548 | 0 |     } | 
| 549 |  |  | 
| 550 | 0 | #ifdef SO_NOSIGPIPE | 
| 551 | 0 |     int set = 1; | 
| 552 |  |     // Set the no-sigpipe option on the socket for BSD systems, other UNIXes | 
| 553 |  |     // should use the MSG_NOSIGNAL flag for every send. | 
| 554 | 0 |     if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 555 | 0 |         LogPrintf("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 556 | 0 |                   NetworkErrorString(WSAGetLastError())); | 
| 557 | 0 |     } | 
| 558 | 0 | #endif | 
| 559 |  |  | 
| 560 |  |     // Set the non-blocking option on the socket. | 
| 561 | 0 |     if (!sock->SetNonBlocking()) { | 
| 562 | 0 |         LogPrintf("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 563 | 0 |         return nullptr; | 
| 564 | 0 |     } | 
| 565 |  |  | 
| 566 | 0 | #ifdef HAVE_SOCKADDR_UN | 
| 567 | 0 |     if (domain == AF_UNIX) return sock; | 
| 568 | 0 | #endif | 
| 569 |  |  | 
| 570 | 0 |     if (protocol == IPPROTO_TCP) { | 
| 571 |  |         // Set the no-delay option (disable Nagle's algorithm) on the TCP socket. | 
| 572 | 0 |         const int on{1}; | 
| 573 | 0 |         if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 574 | 0 |             LogDebug(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n"); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 575 | 0 |         } | 
| 576 | 0 |     } | 
| 577 |  | 
 | 
| 578 | 0 |     return sock; | 
| 579 | 0 | } | 
| 580 |  |  | 
| 581 |  | std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock = CreateSockOS; | 
| 582 |  |  | 
| 583 |  | template<typename... Args> | 
| 584 |  | static void LogConnectFailure(bool manual_connection, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args) | 
| 585 | 0 | { | 
| 586 | 0 |     std::string error_message = tfm::format(fmt, args...); | 
| 587 | 0 |     if (manual_connection) { | 
| 588 | 0 |         LogPrintf("%s\n", error_message);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 589 | 0 |     } else { | 
| 590 | 0 |         LogDebug(BCLog::NET, "%s\n", error_message); | Line | Count | Source |  | 381 | 0 | #define LogDebug(category, ...) LogPrintLevel(category, BCLog::Level::Debug, __VA_ARGS__) | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
 | 
| 591 | 0 |     } | 
| 592 | 0 | } | 
| 593 |  |  | 
| 594 |  | static bool ConnectToSocket(const Sock& sock, struct sockaddr* sockaddr, socklen_t len, const std::string& dest_str, bool manual_connection) | 
| 595 | 0 | { | 
| 596 |  |     // Connect to `sockaddr` using `sock`. | 
| 597 | 0 |     if (sock.Connect(sockaddr, len) == SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 598 | 0 |         int nErr = WSAGetLastError(); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 599 |  |         // WSAEINVAL is here because some legacy version of winsock uses it | 
| 600 | 0 |         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) | Line | Count | Source |  | 53 | 0 | #define WSAEINPROGRESS      EINPROGRESS | 
 |         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) | Line | Count | Source |  | 49 | 0 | #define WSAEWOULDBLOCK      EWOULDBLOCK | 
 |         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) | Line | Count | Source |  | 48 | 0 | #define WSAEINVAL           EINVAL | 
 | 
| 601 | 0 |         { | 
| 602 |  |             // Connection didn't actually fail, but is being established | 
| 603 |  |             // asynchronously. Thus, use async I/O api (select/poll) | 
| 604 |  |             // synchronously to check for successful connection with a timeout. | 
| 605 | 0 |             const Sock::Event requested = Sock::RECV | Sock::SEND; | 
| 606 | 0 |             Sock::Event occurred; | 
| 607 | 0 |             if (!sock.Wait(std::chrono::milliseconds{nConnectTimeout}, requested, &occurred)) { | 
| 608 | 0 |                 LogPrintf("wait for connect to %s failed: %s\n",| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 609 | 0 |                           dest_str, | 
| 610 | 0 |                           NetworkErrorString(WSAGetLastError())); | 
| 611 | 0 |                 return false; | 
| 612 | 0 |             } else if (occurred == 0) { | 
| 613 | 0 |                 LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "connection attempt to %s timed out\n", dest_str); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 614 | 0 |                 return false; | 
| 615 | 0 |             } | 
| 616 |  |  | 
| 617 |  |             // Even if the wait was successful, the connect might not | 
| 618 |  |             // have been successful. The reason for this failure is hidden away | 
| 619 |  |             // in the SO_ERROR for the socket in modern systems. We read it into | 
| 620 |  |             // sockerr here. | 
| 621 | 0 |             int sockerr; | 
| 622 | 0 |             socklen_t sockerr_len = sizeof(sockerr); | 
| 623 | 0 |             if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) == | 
| 624 | 0 |                 SOCKET_ERROR) {| Line | Count | Source |  | 56 | 0 | #define SOCKET_ERROR        -1 | 
 | 
| 625 | 0 |                 LogPrintf("getsockopt() for %s failed: %s\n", dest_str, NetworkErrorString(WSAGetLastError()));| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 626 | 0 |                 return false; | 
| 627 | 0 |             } | 
| 628 | 0 |             if (sockerr != 0) { | 
| 629 | 0 |                 LogConnectFailure(manual_connection, | 
| 630 | 0 |                                   "connect() to %s failed after wait: %s", | 
| 631 | 0 |                                   dest_str, | 
| 632 | 0 |                                   NetworkErrorString(sockerr)); | 
| 633 | 0 |                 return false; | 
| 634 | 0 |             } | 
| 635 | 0 |         } | 
| 636 |  | #ifdef WIN32 | 
| 637 |  |         else if (WSAGetLastError() != WSAEISCONN) | 
| 638 |  | #else | 
| 639 | 0 |         else | 
| 640 | 0 | #endif | 
| 641 | 0 |         { | 
| 642 | 0 |             LogConnectFailure(manual_connection, "connect() to %s failed: %s", dest_str, NetworkErrorString(WSAGetLastError())); | Line | Count | Source |  | 47 | 0 | #define WSAGetLastError()   errno | 
 | 
| 643 | 0 |             return false; | 
| 644 | 0 |         } | 
| 645 | 0 |     } | 
| 646 | 0 |     return true; | 
| 647 | 0 | } | 
| 648 |  |  | 
| 649 |  | std::unique_ptr<Sock> ConnectDirectly(const CService& dest, bool manual_connection) | 
| 650 | 0 | { | 
| 651 | 0 |     auto sock = CreateSock(dest.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP); | 
| 652 | 0 |     if (!sock) { | 
| 653 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Cannot create a socket for connecting to %s\n", dest.ToStringAddrPort()); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 654 | 0 |         return {}; | 
| 655 | 0 |     } | 
| 656 |  |  | 
| 657 |  |     // Create a sockaddr from the specified service. | 
| 658 | 0 |     struct sockaddr_storage sockaddr; | 
| 659 | 0 |     socklen_t len = sizeof(sockaddr); | 
| 660 | 0 |     if (!dest.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { | 
| 661 | 0 |         LogPrintf("Cannot get sockaddr for %s: unsupported network\n", dest.ToStringAddrPort());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 662 | 0 |         return {}; | 
| 663 | 0 |     } | 
| 664 |  |  | 
| 665 | 0 |     if (!ConnectToSocket(*sock, (struct sockaddr*)&sockaddr, len, dest.ToStringAddrPort(), manual_connection)) { | 
| 666 | 0 |         return {}; | 
| 667 | 0 |     } | 
| 668 |  |  | 
| 669 | 0 |     return sock; | 
| 670 | 0 | } | 
| 671 |  |  | 
| 672 |  | std::unique_ptr<Sock> Proxy::Connect() const | 
| 673 | 0 | { | 
| 674 | 0 |     if (!IsValid()) return {}; | 
| 675 |  |  | 
| 676 | 0 |     if (!m_is_unix_socket) return ConnectDirectly(proxy, /*manual_connection=*/true); | 
| 677 |  |  | 
| 678 | 0 | #ifdef HAVE_SOCKADDR_UN | 
| 679 | 0 |     auto sock = CreateSock(AF_UNIX, SOCK_STREAM, 0); | 
| 680 | 0 |     if (!sock) { | 
| 681 | 0 |         LogPrintLevel(BCLog::NET, BCLog::Level::Error, "Cannot create a socket for connecting to %s\n", m_unix_socket_path); | Line | Count | Source |  | 373 | 0 |     do {                                                              \ |  | 374 | 0 |         if (LogAcceptCategory((category), (level))) {                 \ |  | 375 | 0 |             bool rate_limit{level >= BCLog::Level::Info};             \ |  | 376 | 0 |             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \ | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 |  | 377 | 0 |         }                                                             \ |  | 378 | 0 |     } while (0) | 
 | 
| 682 | 0 |         return {}; | 
| 683 | 0 |     } | 
| 684 |  |  | 
| 685 | 0 |     const std::string path{m_unix_socket_path.substr(ADDR_PREFIX_UNIX.length())}; | 
| 686 |  | 
 | 
| 687 | 0 |     struct sockaddr_un addrun; | 
| 688 | 0 |     memset(&addrun, 0, sizeof(addrun)); | 
| 689 | 0 |     addrun.sun_family = AF_UNIX; | 
| 690 |  |     // leave the last char in addrun.sun_path[] to be always '\0' | 
| 691 | 0 |     memcpy(addrun.sun_path, path.c_str(), std::min(sizeof(addrun.sun_path) - 1, path.length())); | 
| 692 | 0 |     socklen_t len = sizeof(addrun); | 
| 693 |  | 
 | 
| 694 | 0 |     if(!ConnectToSocket(*sock, (struct sockaddr*)&addrun, len, path, /*manual_connection=*/true)) { | 
| 695 | 0 |         return {}; | 
| 696 | 0 |     } | 
| 697 |  |  | 
| 698 | 0 |     return sock; | 
| 699 |  | #else | 
| 700 |  |     return {}; | 
| 701 |  | #endif | 
| 702 | 0 | } | 
| 703 |  |  | 
| 704 | 0 | bool SetProxy(enum Network net, const Proxy &addrProxy) { | 
| 705 | 0 |     assert(net >= 0 && net < NET_MAX); | 
| 706 | 0 |     if (!addrProxy.IsValid()) | 
| 707 | 0 |         return false; | 
| 708 | 0 |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 709 | 0 |     proxyInfo[net] = addrProxy; | 
| 710 | 0 |     return true; | 
| 711 | 0 | } | 
| 712 |  |  | 
| 713 | 0 | bool GetProxy(enum Network net, Proxy &proxyInfoOut) { | 
| 714 | 0 |     assert(net >= 0 && net < NET_MAX); | 
| 715 | 0 |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 716 | 0 |     if (!proxyInfo[net].IsValid()) | 
| 717 | 0 |         return false; | 
| 718 | 0 |     proxyInfoOut = proxyInfo[net]; | 
| 719 | 0 |     return true; | 
| 720 | 0 | } | 
| 721 |  |  | 
| 722 | 0 | bool SetNameProxy(const Proxy &addrProxy) { | 
| 723 | 0 |     if (!addrProxy.IsValid()) | 
| 724 | 0 |         return false; | 
| 725 | 0 |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 726 | 0 |     nameProxy = addrProxy; | 
| 727 | 0 |     return true; | 
| 728 | 0 | } | 
| 729 |  |  | 
| 730 | 0 | bool GetNameProxy(Proxy &nameProxyOut) { | 
| 731 | 0 |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 732 | 0 |     if(!nameProxy.IsValid()) | 
| 733 | 0 |         return false; | 
| 734 | 0 |     nameProxyOut = nameProxy; | 
| 735 | 0 |     return true; | 
| 736 | 0 | } | 
| 737 |  |  | 
| 738 | 0 | bool HaveNameProxy() { | 
| 739 | 0 |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 740 | 0 |     return nameProxy.IsValid(); | 
| 741 | 0 | } | 
| 742 |  |  | 
| 743 | 148k | bool IsProxy(const CNetAddr &addr) { | 
| 744 | 148k |     LOCK(g_proxyinfo_mutex); | Line | Count | Source |  | 259 | 148k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 148k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 148k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 148k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 745 | 1.18M |     for (int i = 0; i < NET_MAX; i++1.03M) { | 
| 746 | 1.03M |         if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) | 
| 747 | 0 |             return true; | 
| 748 | 1.03M |     } | 
| 749 | 148k |     return false; | 
| 750 | 148k | } | 
| 751 |  |  | 
| 752 |  | /** | 
| 753 |  |  * Generate unique credentials for Tor stream isolation. Tor will create | 
| 754 |  |  * separate circuits for SOCKS5 proxy connections with different credentials, which | 
| 755 |  |  * makes it harder to correlate the connections. | 
| 756 |  |  */ | 
| 757 |  | class TorStreamIsolationCredentialsGenerator | 
| 758 |  | { | 
| 759 |  | public: | 
| 760 |  |     TorStreamIsolationCredentialsGenerator(): | 
| 761 | 0 |         m_prefix(GenerateUniquePrefix()) { | 
| 762 | 0 |     } | 
| 763 |  |  | 
| 764 |  |     /** Return the next unique proxy credentials. */ | 
| 765 | 0 |     ProxyCredentials Generate() { | 
| 766 | 0 |         ProxyCredentials auth; | 
| 767 | 0 |         auth.username = auth.password = strprintf("%s%i", m_prefix, m_counter);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 768 | 0 |         ++m_counter; | 
| 769 | 0 |         return auth; | 
| 770 | 0 |     } | 
| 771 |  |  | 
| 772 |  |     /** Size of session prefix in bytes. */ | 
| 773 |  |     static constexpr size_t PREFIX_BYTE_LENGTH = 8; | 
| 774 |  | private: | 
| 775 |  |     const std::string m_prefix; | 
| 776 |  |     std::atomic<uint64_t> m_counter; | 
| 777 |  |  | 
| 778 |  |     /** Generate a random prefix for each of the credentials returned by this generator. | 
| 779 |  |      * This makes sure that different launches of the application (either successively or in parallel) | 
| 780 |  |      * will not share the same circuits, as would be the case with a bare counter. | 
| 781 |  |      */ | 
| 782 | 0 |     static std::string GenerateUniquePrefix() { | 
| 783 | 0 |         std::array<uint8_t, PREFIX_BYTE_LENGTH> prefix_bytes; | 
| 784 | 0 |         GetRandBytes(prefix_bytes); | 
| 785 | 0 |         return HexStr(prefix_bytes) + "-"; | 
| 786 | 0 |     } | 
| 787 |  | }; | 
| 788 |  |  | 
| 789 |  | std::unique_ptr<Sock> ConnectThroughProxy(const Proxy& proxy, | 
| 790 |  |                                           const std::string& dest, | 
| 791 |  |                                           uint16_t port, | 
| 792 |  |                                           bool& proxy_connection_failed) | 
| 793 | 0 | { | 
| 794 |  |     // first connect to proxy server | 
| 795 | 0 |     auto sock = proxy.Connect(); | 
| 796 | 0 |     if (!sock) { | 
| 797 | 0 |         proxy_connection_failed = true; | 
| 798 | 0 |         return {}; | 
| 799 | 0 |     } | 
| 800 |  |  | 
| 801 |  |     // do socks negotiation | 
| 802 | 0 |     if (proxy.m_tor_stream_isolation) { | 
| 803 | 0 |         static TorStreamIsolationCredentialsGenerator generator; | 
| 804 | 0 |         ProxyCredentials random_auth{generator.Generate()}; | 
| 805 | 0 |         if (!Socks5(dest, port, &random_auth, *sock)) { | 
| 806 | 0 |             return {}; | 
| 807 | 0 |         } | 
| 808 | 0 |     } else { | 
| 809 | 0 |         if (!Socks5(dest, port, nullptr, *sock)) { | 
| 810 | 0 |             return {}; | 
| 811 | 0 |         } | 
| 812 | 0 |     } | 
| 813 | 0 |     return sock; | 
| 814 | 0 | } | 
| 815 |  |  | 
| 816 |  | CSubNet LookupSubNet(const std::string& subnet_str) | 
| 817 | 0 | { | 
| 818 | 0 |     CSubNet subnet; | 
| 819 | 0 |     assert(!subnet.IsValid()); | 
| 820 | 0 |     if (!ContainsNoNUL(subnet_str)) { | 
| 821 | 0 |         return subnet; | 
| 822 | 0 |     } | 
| 823 |  |  | 
| 824 | 0 |     const size_t slash_pos{subnet_str.find_last_of('/')}; | 
| 825 | 0 |     const std::string str_addr{subnet_str.substr(0, slash_pos)}; | 
| 826 | 0 |     std::optional<CNetAddr> addr{LookupHost(str_addr, /*fAllowLookup=*/false)}; | 
| 827 |  | 
 | 
| 828 | 0 |     if (addr.has_value()) { | 
| 829 | 0 |         addr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); | 
| 830 | 0 |         if (slash_pos != subnet_str.npos) { | 
| 831 | 0 |             const std::string netmask_str{subnet_str.substr(slash_pos + 1)}; | 
| 832 | 0 |             if (const auto netmask{ToIntegral<uint8_t>(netmask_str)}) { | 
| 833 |  |                 // Valid number; assume CIDR variable-length subnet masking. | 
| 834 | 0 |                 subnet = CSubNet{addr.value(), *netmask}; | 
| 835 | 0 |             } else { | 
| 836 |  |                 // Invalid number; try full netmask syntax. Never allow lookup for netmask. | 
| 837 | 0 |                 const std::optional<CNetAddr> full_netmask{LookupHost(netmask_str, /*fAllowLookup=*/false)}; | 
| 838 | 0 |                 if (full_netmask.has_value()) { | 
| 839 | 0 |                     subnet = CSubNet{addr.value(), full_netmask.value()}; | 
| 840 | 0 |                 } | 
| 841 | 0 |             } | 
| 842 | 0 |         } else { | 
| 843 |  |             // Single IP subnet (<ipv4>/32 or <ipv6>/128). | 
| 844 | 0 |             subnet = CSubNet{addr.value()}; | 
| 845 | 0 |         } | 
| 846 | 0 |     } | 
| 847 |  | 
 | 
| 848 | 0 |     return subnet; | 
| 849 | 0 | } | 
| 850 |  |  | 
| 851 |  | bool IsBadPort(uint16_t port) | 
| 852 | 0 | { | 
| 853 |  |     /* Don't forget to update doc/p2p-bad-ports.md if you change this list. */ | 
| 854 |  | 
 | 
| 855 | 0 |     switch (port) { | 
| 856 | 0 |     case 1:     // tcpmux | 
| 857 | 0 |     case 7:     // echo | 
| 858 | 0 |     case 9:     // discard | 
| 859 | 0 |     case 11:    // systat | 
| 860 | 0 |     case 13:    // daytime | 
| 861 | 0 |     case 15:    // netstat | 
| 862 | 0 |     case 17:    // qotd | 
| 863 | 0 |     case 19:    // chargen | 
| 864 | 0 |     case 20:    // ftp data | 
| 865 | 0 |     case 21:    // ftp access | 
| 866 | 0 |     case 22:    // ssh | 
| 867 | 0 |     case 23:    // telnet | 
| 868 | 0 |     case 25:    // smtp | 
| 869 | 0 |     case 37:    // time | 
| 870 | 0 |     case 42:    // name | 
| 871 | 0 |     case 43:    // nicname | 
| 872 | 0 |     case 53:    // domain | 
| 873 | 0 |     case 69:    // tftp | 
| 874 | 0 |     case 77:    // priv-rjs | 
| 875 | 0 |     case 79:    // finger | 
| 876 | 0 |     case 87:    // ttylink | 
| 877 | 0 |     case 95:    // supdup | 
| 878 | 0 |     case 101:   // hostname | 
| 879 | 0 |     case 102:   // iso-tsap | 
| 880 | 0 |     case 103:   // gppitnp | 
| 881 | 0 |     case 104:   // acr-nema | 
| 882 | 0 |     case 109:   // pop2 | 
| 883 | 0 |     case 110:   // pop3 | 
| 884 | 0 |     case 111:   // sunrpc | 
| 885 | 0 |     case 113:   // auth | 
| 886 | 0 |     case 115:   // sftp | 
| 887 | 0 |     case 117:   // uucp-path | 
| 888 | 0 |     case 119:   // nntp | 
| 889 | 0 |     case 123:   // NTP | 
| 890 | 0 |     case 135:   // loc-srv /epmap | 
| 891 | 0 |     case 137:   // netbios | 
| 892 | 0 |     case 139:   // netbios | 
| 893 | 0 |     case 143:   // imap2 | 
| 894 | 0 |     case 161:   // snmp | 
| 895 | 0 |     case 179:   // BGP | 
| 896 | 0 |     case 389:   // ldap | 
| 897 | 0 |     case 427:   // SLP (Also used by Apple Filing Protocol) | 
| 898 | 0 |     case 465:   // smtp+ssl | 
| 899 | 0 |     case 512:   // print / exec | 
| 900 | 0 |     case 513:   // login | 
| 901 | 0 |     case 514:   // shell | 
| 902 | 0 |     case 515:   // printer | 
| 903 | 0 |     case 526:   // tempo | 
| 904 | 0 |     case 530:   // courier | 
| 905 | 0 |     case 531:   // chat | 
| 906 | 0 |     case 532:   // netnews | 
| 907 | 0 |     case 540:   // uucp | 
| 908 | 0 |     case 548:   // AFP (Apple Filing Protocol) | 
| 909 | 0 |     case 554:   // rtsp | 
| 910 | 0 |     case 556:   // remotefs | 
| 911 | 0 |     case 563:   // nntp+ssl | 
| 912 | 0 |     case 587:   // smtp (rfc6409) | 
| 913 | 0 |     case 601:   // syslog-conn (rfc3195) | 
| 914 | 0 |     case 636:   // ldap+ssl | 
| 915 | 0 |     case 989:   // ftps-data | 
| 916 | 0 |     case 990:   // ftps | 
| 917 | 0 |     case 993:   // ldap+ssl | 
| 918 | 0 |     case 995:   // pop3+ssl | 
| 919 | 0 |     case 1719:  // h323gatestat | 
| 920 | 0 |     case 1720:  // h323hostcall | 
| 921 | 0 |     case 1723:  // pptp | 
| 922 | 0 |     case 2049:  // nfs | 
| 923 | 0 |     case 3306:  // MySQL | 
| 924 | 0 |     case 3389:  // RDP / Windows Remote Desktop | 
| 925 | 0 |     case 3659:  // apple-sasl / PasswordServer | 
| 926 | 0 |     case 4045:  // lockd | 
| 927 | 0 |     case 5060:  // sip | 
| 928 | 0 |     case 5061:  // sips | 
| 929 | 0 |     case 5432:  // PostgreSQL | 
| 930 | 0 |     case 5900:  // VNC | 
| 931 | 0 |     case 6000:  // X11 | 
| 932 | 0 |     case 6566:  // sane-port | 
| 933 | 0 |     case 6665:  // Alternate IRC | 
| 934 | 0 |     case 6666:  // Alternate IRC | 
| 935 | 0 |     case 6667:  // Standard IRC | 
| 936 | 0 |     case 6668:  // Alternate IRC | 
| 937 | 0 |     case 6669:  // Alternate IRC | 
| 938 | 0 |     case 6697:  // IRC + TLS | 
| 939 | 0 |     case 10080: // Amanda | 
| 940 | 0 |     case 27017: // MongoDB | 
| 941 | 0 |         return true; | 
| 942 | 0 |     } | 
| 943 | 0 |     return false; | 
| 944 | 0 | } | 
| 945 |  |  | 
| 946 |  | CService MaybeFlipIPv6toCJDNS(const CService& service) | 
| 947 | 0 | { | 
| 948 | 0 |     CService ret{service}; | 
| 949 | 0 |     if (ret.IsIPv6() && ret.HasCJDNSPrefix() && g_reachable_nets.Contains(NET_CJDNS)) { | 
| 950 | 0 |         ret.m_net = NET_CJDNS; | 
| 951 | 0 |     } | 
| 952 | 0 |     return ret; | 
| 953 | 0 | } |