48 ai_hint.ai_socktype = SOCK_STREAM;
49 ai_hint.ai_protocol = IPPROTO_TCP;
51 ai_hint.ai_family = AF_UNSPEC;
58 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
60 addrinfo *ai_res{
nullptr};
61 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
67 addrinfo *ai_trav{ai_res};
68 std::vector<CNetAddr> resolved_addresses;
69 while (ai_trav !=
nullptr) {
70 if (ai_trav->ai_family == AF_INET) {
71 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
72 resolved_addresses.emplace_back(
73 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{
78 reinterpret_cast<sockaddr_in6 *
>(ai_trav->ai_addr)};
79 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
81 ai_trav = ai_trav->ai_next;
85 return resolved_addresses;
91 std::string net =
ToLower(net_in);
102 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed "
103 "in the future. You should use 'onion' instead.\n");
115 return "not_publicly_routable";
136 std::vector<std::string> names;
137 for (
int n = 0; n <
NET_MAX; ++n) {
145 if (append_unroutable) {
152 unsigned int nMaxSolutions,
171 std::vector<CNetAddr> addresses;
173 for (
const CNetAddr &resolved : dns_lookup_function(
name, fAllowLookup)) {
174 if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {
180 if (!resolved.IsInternal()) {
181 addresses.push_back(resolved);
189 unsigned int nMaxSolutions,
bool fAllowLookup,
194 std::string strHost =
name;
195 if (strHost.empty()) {
198 if (strHost.front() ==
'[' && strHost.back() ==
']') {
199 strHost = strHost.substr(1, strHost.size() - 2);
202 return LookupIntern(strHost, nMaxSolutions, fAllowLookup,
203 dns_lookup_function);
208 const std::vector<CNetAddr> addresses{
210 return addresses.empty() ? std::nullopt
211 : std::make_optional(addresses.front());
214std::vector<CService>
Lookup(
const std::string &
name, uint16_t portDefault,
215 bool fAllowLookup,
unsigned int nMaxSolutions,
220 uint16_t port{portDefault};
221 std::string hostname;
225 hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};
226 if (addresses.empty()) {
229 std::vector<CService> services;
230 services.reserve(addresses.size());
231 for (
const auto &addr : addresses) {
232 services.emplace_back(addr, port);
237std::optional<CService>
Lookup(
const std::string &
name, uint16_t portDefault,
240 const std::vector<CService> services{
241 Lookup(
name, portDefault, fAllowLookup, 1, dns_lookup_function)};
243 return services.empty() ? std::nullopt
244 : std::make_optional(services.front());
325 std::chrono::milliseconds timeout,
327 auto curTime{Now<SteadyMilliseconds>()};
328 const auto endTime{curTime + timeout};
329 while (len > 0 && curTime < endTime) {
331 ssize_t ret = sock.
Recv(data, len, 0);
335 }
else if (ret == 0) {
345 const auto remaining =
346 std::chrono::milliseconds{endTime - curTime};
347 const auto timeout_ = std::min(
359 curTime = Now<SteadyMilliseconds>();
368 return "general failure";
370 return "connection not allowed";
372 return "network unreachable";
374 return "host unreachable";
376 return "connection refused";
378 return "TTL expired";
380 return "protocol error";
382 return "address type not supported";
406bool Socks5(
const std::string &strDest, uint16_t port,
410 if (strDest.size() > 255) {
415 std::vector<uint8_t> vSocks5Init;
420 vSocks5Init.push_back(0x02);
425 vSocks5Init.push_back(0x01);
430 if (ret != (ssize_t)vSocks5Init.size()) {
431 LogError(
"Error sending to proxy\n");
437 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() "
438 "timeout or other failure\n",
443 LogError(
"Proxy failed to initialize\n");
448 std::vector<uint8_t> vAuth;
450 vAuth.push_back(0x01);
452 LogError(
"Proxy username or password too long\n");
455 vAuth.push_back(auth->
username.size());
457 vAuth.push_back(auth->
password.size());
460 if (ret != (ssize_t)vAuth.size()) {
461 LogError(
"Error sending authentication to proxy\n");
469 LogError(
"Error reading proxy authentication response\n");
472 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
473 LogError(
"Proxy authentication unsuccessful\n");
479 LogError(
"Proxy requested wrong authentication method %02x\n",
483 std::vector<uint8_t> vSocks5;
489 vSocks5.push_back(0x00);
493 vSocks5.push_back(strDest.size());
494 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
495 vSocks5.push_back((port >> 8) & 0xFF);
496 vSocks5.push_back((port >> 0) & 0xFF);
498 if (ret != (ssize_t)vSocks5.size()) {
499 LogError(
"Error sending to proxy\n");
513 LogError(
"Error while reading proxy response\n");
518 LogError(
"Proxy failed to accept request\n");
523 LogPrintf(
"Socks5() connect to %s:%d failed: %s\n", strDest, port,
528 if (pchRet2[2] != 0x00) {
529 LogError(
"Error: malformed proxy response\n");
532 uint8_t pchRet3[256];
533 switch (pchRet2[3]) {
543 LogError(
"Error reading from proxy\n");
546 int nRecv = pchRet3[0];
552 LogError(
"Error: malformed proxy response\n");
556 LogError(
"Error reading from proxy\n");
561 LogError(
"Error reading from proxy\n");
570 struct sockaddr_storage sockaddr;
571 socklen_t len =
sizeof(sockaddr);
572 if (!address_family.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
573 LogPrintf(
"Cannot create socket for %s: unsupported network\n",
579 SOCKET hSocket = socket(((
struct sockaddr *)&sockaddr)->sa_family,
580 SOCK_STREAM, IPPROTO_TCP);
589 LogPrintf(
"Cannot create connection: non-selectable socket created (fd "
590 ">= FD_SETSIZE ?)\n");
608 LogPrintf(
"CreateSocket: Setting socket to non-blocking "
609 "failed, error %s\n",
613 return std::make_unique<Sock>(hSocket);
619template <
typename... Args>
621 const Args &...args) {
622 std::string error_message =
tfm::format(fmt, args...);
623 if (manual_connection) {
631 int nTimeout,
bool manual_connection) {
633 struct sockaddr_storage sockaddr;
634 socklen_t len =
sizeof(sockaddr);
636 LogPrintf(
"Cannot connect to %s: invalid socket\n",
640 if (!addrConnect.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
641 LogPrintf(
"Cannot connect to %s: unsupported network\n",
647 if (sock.
Connect(
reinterpret_cast<struct sockaddr *
>(&sockaddr), len) ==
658 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested,
660 LogPrintf(
"wait for connect to %s failed: %s\n",
664 }
else if (occurred == 0) {
675 socklen_t sockerr_len =
sizeof(sockerr);
679 LogPrintf(
"getsockopt() for %s failed: %s\n",
686 "connect() to %s failed after wait: %s",
713 proxyInfo[net] = addrProxy;
720 if (!proxyInfo[net].IsValid()) {
723 proxyInfoOut = proxyInfo[net];
732 nameProxy = addrProxy;
738 if (!nameProxy.IsValid()) {
741 nameProxyOut = nameProxy;
747 return nameProxy.IsValid();
752 for (
int i = 0; i <
NET_MAX; i++) {
753 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy)) {
761 uint16_t port,
const Sock &sock,
int nTimeout,
762 bool &outProxyConnectionFailed) {
765 outProxyConnectionFailed =
true;
771 static std::atomic_int counter(0);
774 if (!
Socks5(strDest, port, &random_auth, sock)) {
777 }
else if (!
Socks5(strDest, port, 0, sock)) {
788 size_t slash = strSubnet.find_last_of(
'/');
789 std::string strAddress = strSubnet.substr(0, slash);
790 const std::optional<CNetAddr> network{
793 if (network.has_value()) {
794 if (slash != strSubnet.npos) {
795 std::string strNetmask = strSubnet.substr(slash + 1);
799 ret =
CSubNet(network.value(), n);
803 const std::optional<CNetAddr> netmask{
LookupHost(
804 strNetmask,
false, dns_lookup_function)};
806 if (netmask.has_value()) {
807 ret =
CSubNet(network.value(), netmask.value());
813 ret =
CSubNet(network.value());
824 if (ioctlsocket(hSocket, FIONBIO, &nOne) ==
SOCKET_ERROR) {
826 int fFlags = fcntl(hSocket, F_GETFL, 0);
827 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) ==
SOCKET_ERROR) {
834 if (ioctlsocket(hSocket, FIONBIO, &nZero) ==
SOCKET_ERROR) {
836 int fFlags = fcntl(hSocket, F_GETFL, 0);
837 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) ==
SOCKET_ERROR) {
848 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.
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
std::string ToStringAddrPort() const
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)
#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::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
std::chrono::milliseconds g_socks5_recv_timeout
std::string GetNetworkName(enum Network net)
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &...args)
static IntrRecvError InterruptibleRecv(uint8_t *data, size_t len, std::chrono::milliseconds timeout, const Sock &sock)
Try to read a specified number of bytes from a socket.
SOCKSVersion
SOCKS version.
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.
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...
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::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
static std::vector< CNetAddr > LookupIntern(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
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
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 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.
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.