47 ai_hint.ai_socktype = SOCK_STREAM;
48 ai_hint.ai_protocol = IPPROTO_TCP;
50 ai_hint.ai_family = AF_UNSPEC;
57 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
59 addrinfo* ai_res{
nullptr};
60 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
66 addrinfo* ai_trav{ai_res};
67 std::vector<CNetAddr> resolved_addresses;
68 while (ai_trav !=
nullptr) {
69 if (ai_trav->ai_family == AF_INET) {
70 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
71 resolved_addresses.emplace_back(
reinterpret_cast<sockaddr_in*
>(ai_trav->ai_addr)->sin_addr);
73 if (ai_trav->ai_family == AF_INET6) {
74 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
75 const sockaddr_in6* s6{
reinterpret_cast<sockaddr_in6*
>(ai_trav->ai_addr)};
76 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
78 ai_trav = ai_trav->ai_next;
82 return resolved_addresses;
88 std::string net =
ToLower(net_in);
93 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n");
123 std::vector<std::string> names;
124 for (
int n = 0; n <
NET_MAX; ++n) {
129 if (append_unroutable) {
135static bool LookupIntern(
const std::string&
name, std::vector<CNetAddr>& vIP,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
157 for (
const CNetAddr& resolved : dns_lookup_function(
name, fAllowLookup)) {
158 if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
162 if (!resolved.IsInternal()) {
163 vIP.push_back(resolved);
167 return (vIP.size() > 0);
170bool LookupHost(
const std::string&
name, std::vector<CNetAddr>& vIP,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
175 std::string strHost =
name;
178 if (strHost.front() ==
'[' && strHost.back() ==
']') {
179 strHost = strHost.substr(1, strHost.size() - 2);
182 return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
190 std::vector<CNetAddr> vIP;
198bool Lookup(
const std::string&
name, std::vector<CService>& vAddr, uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
DNSLookupFn dns_lookup_function)
203 uint16_t port{portDefault};
204 std::string hostname;
207 std::vector<CNetAddr> vIP;
208 bool fRet =
LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
211 vAddr.resize(vIP.size());
212 for (
unsigned int i = 0; i < vIP.size(); i++)
222 std::vector<CService> vService;
223 bool fRet =
Lookup(
name, vService, portDefault, fAllowLookup, 1, dns_lookup_function);
238 if(!
Lookup(
name, addr, portDefault,
false, dns_lookup_function))
313 int64_t endTime = curTime + timeout;
314 while (len > 0 && curTime < endTime) {
315 ssize_t ret = sock.
Recv(data, len, 0);
319 }
else if (ret == 0) {
326 const auto remaining = std::chrono::milliseconds{endTime - curTime};
327 const auto timeout = std::min(remaining, std::chrono::milliseconds{
MAX_WAIT_FOR_IO});
347 return "general failure";
349 return "connection not allowed";
351 return "network unreachable";
353 return "host unreachable";
355 return "connection refused";
357 return "TTL expired";
359 return "protocol error";
361 return "address type not supported";
371 if (strDest.size() > 255) {
372 return error(
"Hostname too long");
375 std::vector<uint8_t> vSocks5Init;
378 vSocks5Init.push_back(0x02);
382 vSocks5Init.push_back(0x01);
385 ssize_t ret = sock.
Send(vSocks5Init.data(), vSocks5Init.size(),
MSG_NOSIGNAL);
386 if (ret != (ssize_t)vSocks5Init.size()) {
387 return error(
"Error sending to proxy");
391 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
395 return error(
"Proxy failed to initialize");
399 std::vector<uint8_t> vAuth;
400 vAuth.push_back(0x01);
402 return error(
"Proxy username or password too long");
403 vAuth.push_back(auth->
username.size());
405 vAuth.push_back(auth->
password.size());
408 if (ret != (ssize_t)vAuth.size()) {
409 return error(
"Error sending authentication to proxy");
414 return error(
"Error reading proxy authentication response");
416 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
417 return error(
"Proxy authentication unsuccessful");
422 return error(
"Proxy requested wrong authentication method %02x", pchRet1[1]);
424 std::vector<uint8_t> vSocks5;
427 vSocks5.push_back(0x00);
429 vSocks5.push_back(strDest.size());
430 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
431 vSocks5.push_back((port >> 8) & 0xFF);
432 vSocks5.push_back((port >> 0) & 0xFF);
434 if (ret != (ssize_t)vSocks5.size()) {
435 return error(
"Error sending to proxy");
445 return error(
"Error while reading proxy response");
449 return error(
"Proxy failed to accept request");
456 if (pchRet2[2] != 0x00) {
457 return error(
"Error: malformed proxy response");
459 uint8_t pchRet3[256];
468 return error(
"Error reading from proxy");
470 int nRecv = pchRet3[0];
474 default:
return error(
"Error: malformed proxy response");
477 return error(
"Error reading from proxy");
480 return error(
"Error reading from proxy");
489 struct sockaddr_storage sockaddr;
490 socklen_t len =
sizeof(sockaddr);
491 if (!address_family.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
492 LogPrintf(
"Cannot create socket for %s: unsupported network\n", address_family.
ToString());
497 SOCKET hSocket = socket(((
struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
506 LogPrintf(
"Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
514 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (
void*)&set,
sizeof(
int));
526 return std::make_unique<Sock>(hSocket);
531template<
typename... Args>
533 std::string error_message =
tfm::format(fmt, args...);
534 if (manual_connection) {
544 struct sockaddr_storage sockaddr;
545 socklen_t len =
sizeof(sockaddr);
550 if (!addrConnect.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
551 LogPrintf(
"Cannot connect to %s: unsupported network\n", addrConnect.
ToString());
566 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
567 LogPrintf(
"wait for connect to %s failed: %s\n",
571 }
else if (occurred == 0) {
581 socklen_t sockerr_len =
sizeof(sockerr);
589 "connect() to %s failed after wait: %s",
613 proxyInfo[net] = addrProxy;
620 if (!proxyInfo[net].IsValid())
622 proxyInfoOut = proxyInfo[net];
630 nameProxy = addrProxy;
636 if(!nameProxy.IsValid())
638 nameProxyOut = nameProxy;
644 return nameProxy.IsValid();
649 for (
int i = 0; i <
NET_MAX; i++) {
650 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy))
660 outProxyConnectionFailed =
true;
666 static std::atomic_int counter(0);
668 if (!
Socks5(strDest, port, &random_auth, sock)) {
672 if (!
Socks5(strDest, port, 0, sock)) {
684 size_t slash = strSubnet.find_last_of(
'/');
685 std::vector<CNetAddr> vIP;
687 std::string strAddress = strSubnet.substr(0, slash);
690 if (
LookupHost(strAddress, vIP, 1,
false, dns_lookup_function))
693 if (slash != strSubnet.npos)
695 std::string strNetmask = strSubnet.substr(slash + 1);
705 if (
LookupHost(strNetmask, vIP, 1,
false, dns_lookup_function)) {
706 ret =
CSubNet(network, vIP[0]);
725 if (ioctlsocket(hSocket, FIONBIO, &nOne) ==
SOCKET_ERROR) {
727 int fFlags = fcntl(hSocket, F_GETFL, 0);
728 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) ==
SOCKET_ERROR) {
735 if (ioctlsocket(hSocket, FIONBIO, &nZero) ==
SOCKET_ERROR) {
737 int fFlags = fcntl(hSocket, F_GETFL, 0);
738 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) ==
SOCKET_ERROR) {
750 int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (
const char*)&set,
sizeof(
int));
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToString() const
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
RAII helper class that manages a socket.
virtual ssize_t Send(const void *data, size_t len, int flags) const
send(2) wrapper.
static constexpr Event SEND
If passed to Wait(), then it will wait for readiness to send to the socket.
virtual bool Wait(std::chrono::milliseconds timeout, Event requested, Event *occurred=nullptr) const
Wait for readiness for input (recv) or output (send).
static constexpr Event RECV
If passed to Wait(), then it will wait for readiness to read from the socket.
virtual SOCKET Get() const
Get the value of the contained socket.
virtual int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const
getsockopt(2) wrapper.
virtual int Connect(const sockaddr *addr, socklen_t addr_len) const
connect(2) wrapper.
virtual ssize_t Recv(void *buf, size_t len, int flags) const
recv(2) wrapper.
bool randomize_credentials
#define WSAGetLastError()
static bool IsSelectableSocket(const SOCKET &s)
#define LogPrint(category,...)
@ NET_MAX
Dummy value to indicate the number of NET_* constants.
@ NET_ONION
TOR (v2 or v3)
@ NET_UNROUTABLE
Addresses from these networks are not publicly routable on the global Internet.
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
IntrRecvError
Status codes that can be returned by InterruptibleRecv.
SOCKS5Atyp
Values defined for ATYPE in RFC1928.
SOCKS5Command
Values defined for CMD in RFC1928.
bool GetNameProxy(proxyType &nameProxyOut)
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &... args)
std::string GetNetworkName(enum Network net)
SOCKSVersion
SOCKS version.
int g_socks5_recv_timeout
bool GetProxy(enum Network net, proxyType &proxyInfoOut)
bool LookupSubNet(const std::string &strSubnet, CSubNet &ret, DNSLookupFn dns_lookup_function)
Parse and resolve a specified subnet string into the appropriate internal representation.
static bool LookupIntern(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
bool SetSocketNoDelay(const SOCKET &hSocket)
Set the TCP_NODELAY flag on a socket.
bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest, uint16_t port, const Sock &sock, int nTimeout, bool &outProxyConnectionFailed)
Connect to a specified destination service through a SOCKS5 proxy by first connecting to the SOCKS5 p...
std::function< std::unique_ptr< Sock >(const CService &)> CreateSock
Socket factory.
static IntrRecvError InterruptibleRecv(uint8_t *data, size_t len, int timeout, const Sock &sock)
Try to read a specified number of bytes from a socket.
enum Network ParseNetwork(const std::string &net_in)
SOCKS5Method
Values defined for METHOD in RFC1928.
@ NOAUTH
No authentication required.
@ USER_PASS
Username/password.
@ NO_ACCEPTABLE
No acceptable methods.
bool Socks5(const std::string &strDest, uint16_t port, const ProxyCredentials *auth, const Sock &sock)
Connect to a specified destination service through an already connected SOCKS5 proxy.
static std::string Socks5ErrorString(uint8_t err)
Convert SOCKS5 reply to an error message.
void InterruptSocks5(bool interrupt)
std::unique_ptr< Sock > CreateSockTCP(const CService &address_family)
Create a TCP socket in the given address family.
bool ConnectSocketDirectly(const CService &addrConnect, const Sock &sock, int nTimeout, bool manual_connection)
Try to connect to the specified service on the specified socket.
SOCKS5Reply
Values defined for REP in RFC1928.
@ CMDUNSUPPORTED
Command not supported.
@ NETUNREACHABLE
Network unreachable.
@ GENFAILURE
General failure.
@ CONNREFUSED
Connection refused.
@ ATYPEUNSUPPORTED
Address type not supported.
@ NOTALLOWED
Connection not allowed by ruleset.
@ HOSTUNREACHABLE
Network unreachable.
bool Lookup(const std::string &name, std::vector< CService > &vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
static Mutex g_proxyinfo_mutex
static std::atomic< bool > interruptSocks5Recv(false)
static proxyType proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex)
bool SetNameProxy(const proxyType &addrProxy)
Set the name proxy to use for all connections to nodes specified by a hostname.
bool SetSocketNonBlocking(const SOCKET &hSocket, bool fNonBlocking)
Disable or enable blocking-mode for a socket.
CService LookupNumeric(const std::string &name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
Resolve a service string with a numeric IP to its first corresponding service.
bool IsProxy(const CNetAddr &addr)
std::vector< CNetAddr > WrappedGetAddrInfo(const std::string &name, bool allow_lookup)
Wrapper for getaddrinfo(3).
bool LookupHost(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
bool SetProxy(enum Network net, const proxyType &addrProxy)
std::vector< std::string > GetNetworkNames(bool append_unroutable)
Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE.
static const int DEFAULT_NAME_LOOKUP
-dns default
std::function< std::vector< CNetAddr >(const std::string &, bool)> DNSLookupFn
static const int DEFAULT_CONNECT_TIMEOUT
-timeout default
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
bool CloseSocket(SOCKET &hSocket)
Close socket and set hSocket to INVALID_SOCKET.
static constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
std::string ToLower(const std::string &str)
Returns the lowercase equivalent of the given string.
void SplitHostPort(std::string in, uint16_t &portOut, std::string &hostOut)
bool ParseUInt8(const std::string &str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
bool ValidAsCString(const std::string &str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Credentials for proxy authentication.
bool error(const char *fmt, const Args &... args)
int64_t GetTimeMillis()
Returns the system time (not mockable)