6#if defined(HAVE_CONFIG_H)
7#include <config/bitcoin-config.h>
58 ai_hint.ai_socktype = SOCK_STREAM;
59 ai_hint.ai_protocol = IPPROTO_TCP;
61 ai_hint.ai_family = AF_UNSPEC;
69 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
71 addrinfo *ai_res{
nullptr};
72 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
74 if ((ai_hint.ai_flags & AI_ADDRCONFIG) == AI_ADDRCONFIG) {
78 ai_hint.ai_flags = (ai_hint.ai_flags & ~AI_ADDRCONFIG);
79 const int n_err_retry{
80 getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
81 if (n_err_retry != 0) {
90 addrinfo *ai_trav{ai_res};
91 std::vector<CNetAddr> resolved_addresses;
92 while (ai_trav !=
nullptr) {
93 if (ai_trav->ai_family == AF_INET) {
94 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
95 resolved_addresses.emplace_back(
96 reinterpret_cast<sockaddr_in *
>(ai_trav->ai_addr)->sin_addr);
98 if (ai_trav->ai_family == AF_INET6) {
99 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
100 const sockaddr_in6 *s6{
101 reinterpret_cast<sockaddr_in6 *
>(ai_trav->ai_addr)};
102 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
104 ai_trav = ai_trav->ai_next;
106 freeaddrinfo(ai_res);
108 return resolved_addresses;
114 std::string net =
ToLower(net_in);
121 if (net ==
"onion") {
125 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed "
126 "in the future. You should use 'onion' instead.\n");
138 return "not_publicly_routable";
159 std::vector<std::string> names;
160 for (
int n = 0; n <
NET_MAX; ++n) {
168 if (append_unroutable) {
175 unsigned int nMaxSolutions,
178 if (!ContainsNoNUL(
name)) {
194 std::vector<CNetAddr> addresses;
196 for (
const CNetAddr &resolved : dns_lookup_function(
name, fAllowLookup)) {
197 if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {
203 if (!resolved.IsInternal()) {
204 addresses.push_back(resolved);
212 unsigned int nMaxSolutions,
bool fAllowLookup,
214 if (!ContainsNoNUL(
name)) {
217 std::string strHost =
name;
218 if (strHost.empty()) {
221 if (strHost.front() ==
'[' && strHost.back() ==
']') {
222 strHost = strHost.substr(1, strHost.size() - 2);
225 return LookupIntern(strHost, nMaxSolutions, fAllowLookup,
226 dns_lookup_function);
231 const std::vector<CNetAddr> addresses{
233 return addresses.empty() ? std::nullopt
234 : std::make_optional(addresses.front());
237std::vector<CService>
Lookup(
const std::string &
name, uint16_t portDefault,
238 bool fAllowLookup,
unsigned int nMaxSolutions,
240 if (
name.empty() || !ContainsNoNUL(
name)) {
243 uint16_t port{portDefault};
244 std::string hostname;
248 hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};
249 if (addresses.empty()) {
252 std::vector<CService> services;
253 services.reserve(addresses.size());
254 for (
const auto &addr : addresses) {
255 services.emplace_back(addr, port);
260std::optional<CService>
Lookup(
const std::string &
name, uint16_t portDefault,
263 const std::vector<CService> services{
264 Lookup(
name, portDefault, fAllowLookup, 1, dns_lookup_function)};
266 return services.empty() ? std::nullopt
267 : std::make_optional(services.front());
272 if (!ContainsNoNUL(
name)) {
293 return str.size() + 1 <=
sizeof(((sockaddr_un *)
nullptr)->sun_path);
364 std::chrono::milliseconds timeout,
366 auto curTime{Now<SteadyMilliseconds>()};
367 const auto endTime{curTime + timeout};
368 while (len > 0 && curTime < endTime) {
370 ssize_t ret = sock.
Recv(data, len, 0);
374 }
else if (ret == 0) {
384 const auto remaining =
385 std::chrono::milliseconds{endTime - curTime};
386 const auto timeout_ = std::min(
398 curTime = Now<SteadyMilliseconds>();
407 return "general failure";
409 return "connection not allowed";
411 return "network unreachable";
413 return "host unreachable";
415 return "connection refused";
417 return "TTL expired";
419 return "protocol error";
421 return "address type not supported";
445bool Socks5(
const std::string &strDest, uint16_t port,
449 if (strDest.size() > 255) {
454 std::vector<uint8_t> vSocks5Init;
459 vSocks5Init.push_back(0x02);
464 vSocks5Init.push_back(0x01);
469 if (ret != (ssize_t)vSocks5Init.size()) {
470 LogError(
"Error sending to proxy\n");
476 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() "
477 "timeout or other failure\n",
482 LogError(
"Proxy failed to initialize\n");
487 std::vector<uint8_t> vAuth;
489 vAuth.push_back(0x01);
491 LogError(
"Proxy username or password too long\n");
494 vAuth.push_back(auth->
username.size());
496 vAuth.push_back(auth->
password.size());
499 if (ret != (ssize_t)vAuth.size()) {
500 LogError(
"Error sending authentication to proxy\n");
508 LogError(
"Error reading proxy authentication response\n");
511 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
512 LogError(
"Proxy authentication unsuccessful\n");
518 LogError(
"Proxy requested wrong authentication method %02x\n",
522 std::vector<uint8_t> vSocks5;
528 vSocks5.push_back(0x00);
532 vSocks5.push_back(strDest.size());
533 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
534 vSocks5.push_back((port >> 8) & 0xFF);
535 vSocks5.push_back((port >> 0) & 0xFF);
537 if (ret != (ssize_t)vSocks5.size()) {
538 LogError(
"Error sending to proxy\n");
552 LogError(
"Error while reading proxy response\n");
557 LogError(
"Proxy failed to accept request\n");
562 LogPrintf(
"Socks5() connect to %s:%d failed: %s\n", strDest, port,
567 if (pchRet2[2] != 0x00) {
568 LogError(
"Error: malformed proxy response\n");
571 uint8_t pchRet3[256];
572 switch (pchRet2[3]) {
582 LogError(
"Error reading from proxy\n");
585 int nRecv = pchRet3[0];
591 LogError(
"Error: malformed proxy response\n");
595 LogError(
"Error reading from proxy\n");
600 LogError(
"Error reading from proxy\n");
607std::unique_ptr<Sock>
CreateSockOS(
int domain,
int type,
int protocol) {
609 if (domain == AF_UNSPEC) {
614 SOCKET hSocket = socket(domain, type, protocol);
619 auto sock = std::make_unique<Sock>(hSocket);
621 if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNIX) {
627 if (!sock->IsSelectable()) {
628 LogPrintf(
"Cannot create connection: non-selectable socket created (fd "
629 ">= FD_SETSIZE ?)\n");
640 "Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",
646 if (!sock->SetNonBlocking()) {
647 LogPrintf(
"CreateSocket: Setting socket to non-blocking "
648 "failed, error %s\n",
654 if (domain == AF_UNIX) {
659 if (protocol == IPPROTO_TCP) {
663 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on,
sizeof(on)) ==
666 "socket, continuing anyway\n");
675template <
typename... Args>
677 const Args &...args) {
678 std::string error_message =
tfm::format(fmt, args...);
679 if (manual_connection) {
687 socklen_t len,
const std::string &dest_str,
688 bool manual_connection) {
700 if (!sock.
Wait(std::chrono::milliseconds{nConnectTimeout},
701 requested, &occurred)) {
702 LogPrintf(
"wait for connect to %s failed: %s\n", dest_str,
705 }
else if (occurred == 0) {
716 socklen_t sockerr_len =
sizeof(sockerr);
720 LogPrintf(
"getsockopt() for %s failed: %s\n", dest_str,
726 "connect() to %s failed after wait: %s",
746 bool manual_connection) {
750 "Cannot create a socket for connecting to %s\n",
756 struct sockaddr_storage sockaddr;
757 socklen_t len =
sizeof(sockaddr);
758 if (!dest.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
759 LogPrintf(
"Cannot get sockaddr for %s: unsupported network\n",
782 auto sock =
CreateSock(AF_UNIX, SOCK_STREAM, 0);
785 "Cannot create a socket for connecting to %s\n",
790 const std::string path{
793 struct sockaddr_un addrun;
794 memset(&addrun, 0,
sizeof(addrun));
795 addrun.sun_family = AF_UNIX;
797 memcpy(addrun.sun_path, path.c_str(),
798 std::min(
sizeof(addrun.sun_path) - 1, path.length()));
799 socklen_t len =
sizeof(addrun);
818 proxyInfo[net] = addrProxy;
825 if (!proxyInfo[net].IsValid()) {
828 proxyInfoOut = proxyInfo[net];
837 nameProxy = addrProxy;
843 if (!nameProxy.IsValid()) {
846 nameProxyOut = nameProxy;
852 return nameProxy.IsValid();
857 for (
int i = 0; i <
NET_MAX; i++) {
858 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy)) {
866 const std::string &dest,
868 bool &proxy_connection_failed) {
872 proxy_connection_failed =
true;
879 static std::atomic_int counter(0);
882 if (!
Socks5(dest, port, &random_auth, *sock)) {
885 }
else if (!
Socks5(dest, port,
nullptr, *sock)) {
893 if (!ContainsNoNUL(strSubnet)) {
896 size_t slash = strSubnet.find_last_of(
'/');
897 std::string strAddress = strSubnet.substr(0, slash);
898 const std::optional<CNetAddr> network{
901 if (network.has_value()) {
902 if (slash != strSubnet.npos) {
903 std::string strNetmask = strSubnet.substr(slash + 1);
907 ret =
CSubNet(network.value(), n);
911 const std::optional<CNetAddr> netmask{
LookupHost(
912 strNetmask,
false, dns_lookup_function)};
914 if (netmask.has_value()) {
915 ret =
CSubNet(network.value(), netmask.value());
921 ret =
CSubNet(network.value());
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.
sa_family_t GetSAFamily() const
Get the address family.
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.
bool m_randomize_credentials
std::unique_ptr< Sock > Connect() const
std::string m_unix_socket_path
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
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 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.
#define WSAGetLastError()
#define LogPrintLevel(category, level,...)
#define LogDebug(category,...)
bool ContainsNoNUL(std::string_view str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
@ 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.
std::unique_ptr< Sock > ConnectDirectly(const CService &dest, bool manual_connection)
Create a socket and try to connect to the specified service.
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 SetNameProxy(const Proxy &addrProxy)
Set the name proxy to use for all connections to nodes specified by a hostname.
bool LookupSubNet(const std::string &strSubnet, CSubNet &ret, DNSLookupFn dns_lookup_function)
Parse and resolve a specified subnet string into the appropriate internal representation.
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)
bool SetProxy(enum Network net, const Proxy &addrProxy)
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)
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
std::unique_ptr< Sock > CreateSockOS(int domain, int type, int protocol)
Create a real socket from the operating system.
bool GetProxy(enum Network net, Proxy &proxyInfoOut)
static std::atomic< bool > interruptSocks5Recv(false)
static bool ConnectToSocket(const Sock &sock, struct sockaddr *sockaddr, socklen_t len, const std::string &dest_str, bool manual_connection)
std::unique_ptr< Sock > ConnectThroughProxy(const Proxy &proxy, const std::string &dest, uint16_t port, bool &proxy_connection_failed)
Connect to a specified destination service through a SOCKS5 proxy by first connecting to the SOCKS5 p...
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
bool IsUnixSocketPath(const std::string &name)
Check if a string is a valid UNIX domain socket path.
bool GetNameProxy(Proxy &nameProxyOut)
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).
std::vector< std::string > GetNetworkNames(bool append_unroutable)
Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE.
std::unique_ptr< Sock > ConnectDirectly(const CService &dest, bool manual_connection)
Create a socket and try to connect to the specified service.
static const int DEFAULT_NAME_LOOKUP
-dns default
const std::string ADDR_PREFIX_UNIX
Prefix for unix domain socket addresses (which are local filesystem paths)
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
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.
static constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
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.
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.