49 ai_hint.ai_socktype = SOCK_STREAM;
50 ai_hint.ai_protocol = IPPROTO_TCP;
52 ai_hint.ai_family = AF_UNSPEC;
59 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
61 addrinfo* ai_res{
nullptr};
62 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
68 addrinfo* ai_trav{ai_res};
69 std::vector<CNetAddr> resolved_addresses;
70 while (ai_trav !=
nullptr) {
71 if (ai_trav->ai_family == AF_INET) {
72 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
73 resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr);
75 if (ai_trav->ai_family == AF_INET6) {
76 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
77 const sockaddr_in6* s6{
reinterpret_cast<sockaddr_in6*
>(ai_trav->ai_addr)};
78 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
80 ai_trav = ai_trav->ai_next;
84 return resolved_addresses;
90 std::string net =
ToLower(net_in);
95 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n");
122 std::vector<std::string> names;
123 for (
int n = 0; n <
NET_MAX; ++n) {
128 if (append_unroutable) {
134 static bool LookupIntern(
const std::string&
name, std::vector<CNetAddr>& vIP,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
156 for (
const CNetAddr& resolved : dns_lookup_function(
name, fAllowLookup)) {
157 if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
161 if (!resolved.IsInternal()) {
162 vIP.push_back(resolved);
166 return (vIP.size() > 0);
169 bool LookupHost(
const std::string&
name, std::vector<CNetAddr>& vIP,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
174 std::string strHost =
name;
177 if (strHost.front() ==
'[' && strHost.back() ==
']') {
178 strHost = strHost.substr(1, strHost.size() - 2);
181 return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
189 std::vector<CNetAddr> vIP;
197 bool Lookup(
const std::string&
name, std::vector<CService>& vAddr, uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
DNSLookupFn dns_lookup_function)
202 uint16_t port{portDefault};
203 std::string hostname;
206 std::vector<CNetAddr> vIP;
207 bool fRet =
LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
210 vAddr.resize(vIP.size());
211 for (
unsigned int i = 0; i < vIP.size(); i++)
221 std::vector<CService> vService;
222 bool fRet =
Lookup(
name, vService, portDefault, fAllowLookup, 1, dns_lookup_function);
237 if(!
Lookup(
name, addr, portDefault,
false, dns_lookup_function))
312 int64_t endTime = curTime + timeout;
313 while (len > 0 && curTime < endTime) {
314 ssize_t ret = sock.
Recv(data, len, 0);
318 }
else if (ret == 0) {
325 const auto remaining = std::chrono::milliseconds{endTime - curTime};
326 const auto timeout = std::min(remaining, std::chrono::milliseconds{
MAX_WAIT_FOR_IO});
346 return "general failure";
348 return "connection not allowed";
350 return "network unreachable";
352 return "host unreachable";
354 return "connection refused";
356 return "TTL expired";
358 return "protocol error";
360 return "address type not supported";
370 if (strDest.size() > 255) {
371 return error(
"Hostname too long");
374 std::vector<uint8_t> vSocks5Init;
377 vSocks5Init.push_back(0x02);
381 vSocks5Init.push_back(0x01);
384 ssize_t ret = sock.
Send(vSocks5Init.data(), vSocks5Init.size(),
MSG_NOSIGNAL);
385 if (ret != (ssize_t)vSocks5Init.size()) {
386 return error(
"Error sending to proxy");
390 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
394 return error(
"Proxy failed to initialize");
398 std::vector<uint8_t> vAuth;
399 vAuth.push_back(0x01);
401 return error(
"Proxy username or password too long");
402 vAuth.push_back(auth->
username.size());
404 vAuth.push_back(auth->
password.size());
407 if (ret != (ssize_t)vAuth.size()) {
408 return error(
"Error sending authentication to proxy");
413 return error(
"Error reading proxy authentication response");
415 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
416 return error(
"Proxy authentication unsuccessful");
421 return error(
"Proxy requested wrong authentication method %02x", pchRet1[1]);
423 std::vector<uint8_t> vSocks5;
426 vSocks5.push_back(0x00);
428 vSocks5.push_back(strDest.size());
429 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
430 vSocks5.push_back((port >> 8) & 0xFF);
431 vSocks5.push_back((port >> 0) & 0xFF);
433 if (ret != (ssize_t)vSocks5.size()) {
434 return error(
"Error sending to proxy");
444 return error(
"Error while reading proxy response");
448 return error(
"Proxy failed to accept request");
455 if (pchRet2[2] != 0x00) {
456 return error(
"Error: malformed proxy response");
458 uint8_t pchRet3[256];
467 return error(
"Error reading from proxy");
469 int nRecv = pchRet3[0];
473 default:
return error(
"Error: malformed proxy response");
476 return error(
"Error reading from proxy");
479 return error(
"Error reading from proxy");
488 struct sockaddr_storage sockaddr;
489 socklen_t len =
sizeof(sockaddr);
490 if (!address_family.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
491 LogPrintf(
"Cannot create socket for %s: unsupported network\n", address_family.
ToString());
496 SOCKET hSocket = socket(((
struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
505 LogPrintf(
"Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
513 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (
void*)&
set,
sizeof(
int));
525 return std::make_unique<Sock>(hSocket);
530 template<
typename... Args>
532 std::string error_message =
tfm::format(fmt, args...);
533 if (manual_connection) {
543 struct sockaddr_storage sockaddr;
544 socklen_t len =
sizeof(sockaddr);
549 if (!addrConnect.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
550 LogPrintf(
"Cannot connect to %s: unsupported network\n", addrConnect.
ToString());
565 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
566 LogPrintf(
"wait for connect to %s failed: %s\n",
570 }
else if (occurred == 0) {
580 socklen_t sockerr_len =
sizeof(sockerr);
588 "connect() to %s failed after wait: %s",
612 proxyInfo[net] = addrProxy;
619 if (!proxyInfo[net].IsValid())
621 proxyInfoOut = proxyInfo[net];
629 nameProxy = addrProxy;
635 if(!nameProxy.IsValid())
637 nameProxyOut = nameProxy;
643 return nameProxy.IsValid();
648 for (
int i = 0; i <
NET_MAX; i++) {
649 if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy))
659 outProxyConnectionFailed =
true;
665 static std::atomic_int counter(0);
667 if (!
Socks5(strDest, port, &random_auth, sock)) {
671 if (!
Socks5(strDest, port, 0, sock)) {
683 size_t slash = strSubnet.find_last_of(
'/');
684 std::vector<CNetAddr> vIP;
686 std::string strAddress = strSubnet.substr(0, slash);
689 if (
LookupHost(strAddress, vIP, 1,
false, dns_lookup_function))
692 if (slash != strSubnet.npos)
694 std::string strNetmask = strSubnet.substr(slash + 1);
704 if (
LookupHost(strNetmask, vIP, 1,
false, dns_lookup_function)) {
705 ret =
CSubNet(network, vIP[0]);
724 if (ioctlsocket(hSocket, FIONBIO, &nOne) ==
SOCKET_ERROR) {
726 int fFlags = fcntl(hSocket, F_GETFL, 0);
727 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) ==
SOCKET_ERROR) {
734 if (ioctlsocket(hSocket, FIONBIO, &nZero) ==
SOCKET_ERROR) {
736 int fFlags = fcntl(hSocket, F_GETFL, 0);
737 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) ==
SOCKET_ERROR) {
749 int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (
const char*)&
set,
sizeof(
int));
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.
SOCKS5Reply
Values defined for REP in RFC1928.
int g_socks5_recv_timeout
std::string ToLower(const std::string &str)
Returns the lowercase equivalent of the given string.
bool LookupSubNet(const std::string &strSubnet, CSubNet &ret, DNSLookupFn dns_lookup_function)
Parse and resolve a specified subnet string into the appropriate internal representation.
#define LogPrint(category,...)
A set of addresses that represent the hash of a string or FQDN.
Dummy value to indicate the number of NET_* constants.
static bool IsSelectableSocket(const SOCKET &s)
static Mutex g_proxyinfo_mutex
int64_t GetTimeMillis()
Returns the system time (not mockable)
static proxyType proxyInfo [NET_MAX] GUARDED_BY(g_proxyinfo_mutex)
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &... args)
bool GetNameProxy(proxyType &nameProxyOut)
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 SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
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.
virtual ssize_t Recv(void *buf, size_t len, int flags) const
recv(2) wrapper.
bool SetNameProxy(const proxyType &addrProxy)
Set the name proxy to use for all connections to nodes specified by a hostname.
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.
#define WSAGetLastError()
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...
virtual bool Wait(std::chrono::milliseconds timeout, Event requested, Event *occurred=nullptr) const
Wait for readiness for input (recv) or output (send).
std::unique_ptr< Sock > CreateSockTCP(const CService &address_family)
Create a TCP socket in the given address family.
No authentication required.
SOCKS5Command
Values defined for CMD in RFC1928.
static constexpr Event SEND
If passed to Wait(), then it will wait for readiness to send to the socket.
virtual int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const
getsockopt(2) wrapper.
bool ConnectSocketDirectly(const CService &addrConnect, const Sock &sock, int nTimeout, bool manual_connection)
Try to connect to the specified service on the specified socket.
bool randomize_credentials
std::vector< CNetAddr > WrappedGetAddrInfo(const std::string &name, bool allow_lookup)
Wrapper for getaddrinfo(3).
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
virtual ssize_t Send(const void *data, size_t len, int flags) const
send(2) wrapper.
bool CloseSocket(SOCKET &hSocket)
Close socket and set hSocket to INVALID_SOCKET.
A combination of a network address (CNetAddr) and a (TCP) port.
Credentials for proxy authentication.
IntrRecvError
Status codes that can be returned by InterruptibleRecv.
bool IsProxy(const CNetAddr &addr)
SOCKSVersion
SOCKS version.
static std::atomic< bool > interruptSocks5Recv(false)
static const int DEFAULT_NAME_LOOKUP
-dns default
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
static std::string Socks5ErrorString(uint8_t err)
Convert SOCKS5 reply to an error message.
std::vector< std::string > GetNetworkNames(bool append_unroutable)
Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE.
SOCKS5Method
Values defined for METHOD in RFC1928.
bool SetProxy(enum Network net, const proxyType &addrProxy)
bool SetSocketNonBlocking(const SOCKET &hSocket, bool fNonBlocking)
Disable or enable blocking-mode for a socket.
enum Network ParseNetwork(const std::string &net_in)
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.
static constexpr Event RECV
If passed to Wait(), then it will wait for readiness to read from the socket.
std::function< std::vector< CNetAddr >(const std::string &, bool)> DNSLookupFn
bool SetSocketNoDelay(const SOCKET &hSocket)
Set the TCP_NODELAY flag on a socket.
virtual SOCKET Get() const
Get the value of the contained socket.
static const int DEFAULT_CONNECT_TIMEOUT
-timeout default
bool ValidAsCString(const std::string &str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
void InterruptSocks5(bool interrupt)
std::string ToString() const
bool GetProxy(enum Network net, proxyType &proxyInfoOut)
RAII helper class that manages a socket.
std::function< std::unique_ptr< Sock >const CService &)> CreateSock
Socket factory.
Address type not supported.
bool ParseUInt8(const std::string &str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
Connection not allowed by ruleset.
std::string GetNetworkName(enum Network net)
SOCKS5Atyp
Values defined for ATYPE in RFC1928.
bool error(const char *fmt, const Args &... args)
static bool LookupIntern(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
void SplitHostPort(std::string in, uint16_t &portOut, std::string &hostOut)
virtual int Connect(const sockaddr *addr, socklen_t addr_len) const
connect(2) wrapper.
static constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
Addresses from these networks are not publicly routable on the global Internet.