50 ai_hint.ai_socktype = SOCK_STREAM;
51 ai_hint.ai_protocol = IPPROTO_TCP;
53 ai_hint.ai_family = AF_UNSPEC;
60 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
62 addrinfo *ai_res{
nullptr};
63 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
69 addrinfo *ai_trav{ai_res};
70 std::vector<CNetAddr> resolved_addresses;
71 while (ai_trav !=
nullptr) {
72 if (ai_trav->ai_family == AF_INET) {
73 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
74 resolved_addresses.emplace_back(
75 reinterpret_cast<sockaddr_in *
>(ai_trav->ai_addr)->sin_addr);
77 if (ai_trav->ai_family == AF_INET6) {
78 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
79 const sockaddr_in6 *s6{
80 reinterpret_cast<sockaddr_in6 *
>(ai_trav->ai_addr)};
81 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
83 ai_trav = ai_trav->ai_next;
87 return resolved_addresses;
93 std::string net =
ToLower(net_in);
100 if (net ==
"onion") {
104 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed "
105 "in the future. You should use 'onion' instead.\n");
117 return "not_publicly_routable";
138 std::vector<std::string> names;
139 for (
int n = 0; n <
NET_MAX; ++n) {
147 if (append_unroutable) {
154 unsigned int nMaxSolutions,
bool fAllowLookup,
176 for (
const CNetAddr &resolved : dns_lookup_function(
name, fAllowLookup)) {
177 if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
183 if (!resolved.IsInternal()) {
184 vIP.push_back(resolved);
188 return (vIP.size() > 0);
192 unsigned int nMaxSolutions,
bool fAllowLookup,
197 std::string strHost =
name;
198 if (strHost.empty()) {
201 if (strHost.front() ==
'[' && strHost.back() ==
']') {
202 strHost = strHost.substr(1, strHost.size() - 2);
205 return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup,
206 dns_lookup_function);
214 std::vector<CNetAddr> vIP;
223bool Lookup(
const std::string &
name, std::vector<CService> &vAddr,
224 uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
229 uint16_t port{portDefault};
230 std::string hostname;
233 std::vector<CNetAddr> vIP;
234 bool fRet =
LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup,
235 dns_lookup_function);
239 vAddr.resize(vIP.size());
240 for (
unsigned int i = 0; i < vIP.size(); i++) {
247 bool fAllowLookup,
DNSLookupFn dns_lookup_function) {
251 std::vector<CService> vService;
252 bool fRet =
Lookup(
name, vService, portDefault, fAllowLookup, 1,
253 dns_lookup_function);
269 if (!
Lookup(
name, addr, portDefault,
false, dns_lookup_function)) {
343 int64_t endTime = curTime + timeout;
344 while (len > 0 && curTime < endTime) {
346 ssize_t ret = sock.
Recv(data, len, 0);
350 }
else if (ret == 0) {
360 const auto remaining =
361 std::chrono::milliseconds{endTime - curTime};
362 const auto timeout_ = std::min(
383 return "general failure";
385 return "connection not allowed";
387 return "network unreachable";
389 return "host unreachable";
391 return "connection refused";
393 return "TTL expired";
395 return "protocol error";
397 return "address type not supported";
421bool Socks5(
const std::string &strDest, uint16_t port,
425 if (strDest.size() > 255) {
426 return error(
"Hostname too long");
429 std::vector<uint8_t> vSocks5Init;
434 vSocks5Init.push_back(0x02);
439 vSocks5Init.push_back(0x01);
444 if (ret != (ssize_t)vSocks5Init.size()) {
445 return error(
"Error sending to proxy");
450 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() "
451 "timeout or other failure\n",
456 return error(
"Proxy failed to initialize");
460 std::vector<uint8_t> vAuth;
462 vAuth.push_back(0x01);
464 return error(
"Proxy username or password too long");
466 vAuth.push_back(auth->
username.size());
468 vAuth.push_back(auth->
password.size());
471 if (ret != (ssize_t)vAuth.size()) {
472 return error(
"Error sending authentication to proxy");
479 return error(
"Error reading proxy authentication response");
481 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
482 return error(
"Proxy authentication unsuccessful");
487 return error(
"Proxy requested wrong authentication method %02x",
490 std::vector<uint8_t> vSocks5;
496 vSocks5.push_back(0x00);
500 vSocks5.push_back(strDest.size());
501 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
502 vSocks5.push_back((port >> 8) & 0xFF);
503 vSocks5.push_back((port >> 0) & 0xFF);
505 if (ret != (ssize_t)vSocks5.size()) {
506 return error(
"Error sending to proxy");
519 return error(
"Error while reading proxy response");
523 return error(
"Proxy failed to accept request");
527 LogPrintf(
"Socks5() connect to %s:%d failed: %s\n", strDest, port,
532 if (pchRet2[2] != 0x00) {
533 return error(
"Error: malformed proxy response");
535 uint8_t pchRet3[256];
536 switch (pchRet2[3]) {
546 return error(
"Error reading from proxy");
548 int nRecv = pchRet3[0];
554 return error(
"Error: malformed proxy response");
557 return error(
"Error reading from proxy");
561 return error(
"Error reading from proxy");
569 struct sockaddr_storage sockaddr;
570 socklen_t len =
sizeof(sockaddr);
571 if (!address_family.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
572 LogPrintf(
"Cannot create socket for %s: unsupported network\n",
578 SOCKET hSocket = socket(((
struct sockaddr *)&sockaddr)->sa_family,
579 SOCK_STREAM, IPPROTO_TCP);
588 LogPrintf(
"Cannot create connection: non-selectable socket created (fd "
589 ">= FD_SETSIZE ?)\n");
607 LogPrintf(
"CreateSocket: Setting socket to non-blocking "
608 "failed, error %s\n",
612 return std::make_unique<Sock>(hSocket);
618template <
typename... Args>
620 const Args &...args) {
621 std::string error_message =
tfm::format(fmt, args...);
622 if (manual_connection) {
630 int nTimeout,
bool manual_connection) {
632 struct sockaddr_storage sockaddr;
633 socklen_t len =
sizeof(sockaddr);
635 LogPrintf(
"Cannot connect to %s: invalid socket\n",
639 if (!addrConnect.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
640 LogPrintf(
"Cannot connect to %s: unsupported network\n",
646 if (sock.
Connect(
reinterpret_cast<struct sockaddr *
>(&sockaddr), len) ==
657 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested,
659 LogPrintf(
"wait for connect to %s failed: %s\n",
663 }
else if (occurred == 0) {
674 socklen_t sockerr_len =
sizeof(sockerr);
678 LogPrintf(
"getsockopt() for %s failed: %s\n",
685 manual_connection,
"connect() to %s failed after wait: %s",
711 proxyInfo[net] = addrProxy;
718 if (!proxyInfo[net].IsValid()) {
721 proxyInfoOut = proxyInfo[net];
730 nameProxy = addrProxy;
736 if (!nameProxy.IsValid()) {
739 nameProxyOut = nameProxy;
745 return nameProxy.IsValid();
750 for (
int i = 0; i <
NET_MAX; i++) {
751 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy)) {
759 uint16_t port,
const Sock &sock,
int nTimeout,
760 bool &outProxyConnectionFailed) {
763 outProxyConnectionFailed =
true;
769 static std::atomic_int counter(0);
772 if (!
Socks5(strDest, port, &random_auth, sock)) {
775 }
else if (!
Socks5(strDest, port, 0, sock)) {
786 size_t slash = strSubnet.find_last_of(
'/');
787 std::vector<CNetAddr> vIP;
789 std::string strAddress = strSubnet.substr(0, slash);
791 if (
LookupHost(strAddress, vIP, 1,
false, dns_lookup_function)) {
793 if (slash != strSubnet.npos) {
794 std::string strNetmask = strSubnet.substr(slash + 1);
804 dns_lookup_function)) {
805 ret =
CSubNet(network, vIP[0]);
821 if (ioctlsocket(hSocket, FIONBIO, &nOne) ==
SOCKET_ERROR) {
823 int fFlags = fcntl(hSocket, F_GETFL, 0);
824 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) ==
SOCKET_ERROR) {
831 if (ioctlsocket(hSocket, FIONBIO, &nZero) ==
SOCKET_ERROR) {
833 int fFlags = fcntl(hSocket, F_GETFL, 0);
834 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) ==
SOCKET_ERROR) {
845 int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY,
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.
Different type to mark Mutex at global scope.
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)
bool error(const char *fmt, const Args &...args)
#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)
std::string GetNetworkName(enum Network net)
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &...args)
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...
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.
std::function< std::unique_ptr< Sock >(const CService &)> CreateSock
Socket factory.
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.
static GlobalMutex g_proxyinfo_mutex
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 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)
bool IsBadPort(uint16_t port)
Determine if a port is "bad" from the perspective of attempting to connect to a node on that port.
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.
bool ContainsNoNUL(std::string_view str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Credentials for proxy authentication.
int64_t GetTimeMillis()
Returns the system time (not mockable)
bool ParseUInt8(std::string_view str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
void SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.