6 #if defined(HAVE_CONFIG_H)
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");
101 if (net ==
"cjdns") {
125 std::vector<std::string> names;
126 for (
int n = 0; n <
NET_MAX; ++n) {
131 if (append_unroutable) {
137 static std::vector<CNetAddr>
LookupIntern(
const std::string&
name,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
151 std::vector<CNetAddr> addresses;
153 for (
const CNetAddr& resolved : dns_lookup_function(
name, fAllowLookup)) {
154 if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {
158 if (!resolved.IsInternal()) {
159 addresses.push_back(resolved);
166 std::vector<CNetAddr>
LookupHost(
const std::string&
name,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
169 std::string strHost =
name;
170 if (strHost.empty())
return {};
171 if (strHost.front() ==
'[' && strHost.back() ==
']') {
172 strHost = strHost.substr(1, strHost.size() - 2);
175 return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function);
180 const std::vector<CNetAddr> addresses{
LookupHost(
name, 1, fAllowLookup, dns_lookup_function)};
181 return addresses.empty() ? std::nullopt : std::make_optional(addresses.front());
184 std::vector<CService>
Lookup(
const std::string&
name, uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
DNSLookupFn dns_lookup_function)
189 uint16_t port{portDefault};
190 std::string hostname;
193 const std::vector<CNetAddr> addresses{
LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};
194 if (addresses.empty())
return {};
195 std::vector<CService> services;
196 services.reserve(addresses.size());
197 for (
const auto& addr : addresses)
198 services.emplace_back(addr, port);
202 std::optional<CService>
Lookup(
const std::string&
name, uint16_t portDefault,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
204 const std::vector<CService> services{
Lookup(
name, portDefault, fAllowLookup, 1, dns_lookup_function)};
206 return services.empty() ? std::nullopt : std::make_optional(services.front());
229 if (str.size() + 1 >
sizeof(((sockaddr_un*)
nullptr)->sun_path))
return false;
305 auto curTime{Now<SteadyMilliseconds>()};
306 const auto endTime{curTime + timeout};
307 while (len > 0 && curTime < endTime) {
308 ssize_t
ret = sock.
Recv(data, len, 0);
312 }
else if (
ret == 0) {
319 const auto remaining = std::chrono::milliseconds{endTime - curTime};
320 const auto timeout = std::min(remaining, std::chrono::milliseconds{
MAX_WAIT_FOR_IO});
331 curTime = Now<SteadyMilliseconds>();
341 return "general failure";
343 return "connection not allowed";
345 return "network unreachable";
347 return "host unreachable";
349 return "connection refused";
351 return "TTL expired";
353 return "protocol error";
355 return "address type not supported";
366 if (strDest.size() > 255) {
371 std::vector<uint8_t> vSocks5Init;
374 vSocks5Init.push_back(0x02);
378 vSocks5Init.push_back(0x01);
384 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
388 LogError(
"Proxy failed to initialize\n");
393 std::vector<uint8_t> vAuth;
394 vAuth.push_back(0x01);
396 LogError(
"Proxy username or password too long\n");
399 vAuth.push_back(auth->
username.size());
401 vAuth.push_back(auth->
password.size());
407 LogError(
"Error reading proxy authentication response\n");
410 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
411 LogError(
"Proxy authentication unsuccessful\n");
417 LogError(
"Proxy requested wrong authentication method %02x\n", pchRet1[1]);
420 std::vector<uint8_t> vSocks5;
423 vSocks5.push_back(0x00);
425 vSocks5.push_back(strDest.size());
426 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
427 vSocks5.push_back((port >> 8) & 0xFF);
428 vSocks5.push_back((port >> 0) & 0xFF);
438 LogError(
"Error while reading proxy response\n");
443 LogError(
"Proxy failed to accept request\n");
451 if (pchRet2[2] != 0x00) {
452 LogError(
"Error: malformed proxy response\n");
455 uint8_t pchRet3[256];
456 switch (pchRet2[3]) {
462 LogError(
"Error reading from proxy\n");
465 int nRecv = pchRet3[0];
470 LogError(
"Error: malformed proxy response\n");
475 LogError(
"Error reading from proxy\n");
479 LogError(
"Error reading from proxy\n");
484 }
catch (
const std::runtime_error& e) {
485 LogError(
"Error during SOCKS5 proxy handshake: %s\n", e.what());
493 if (address_family == AF_UNSPEC)
return nullptr;
495 int protocol{IPPROTO_TCP};
497 if (address_family == AF_UNIX) protocol = 0;
501 SOCKET hSocket = socket(address_family, SOCK_STREAM, protocol);
506 auto sock = std::make_unique<Sock>(hSocket);
510 if (!sock->IsSelectable()) {
511 LogPrintf(
"Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
519 if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, (
void*)&set,
sizeof(
int)) ==
SOCKET_ERROR) {
520 LogPrintf(
"Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",
526 if (!sock->SetNonBlocking()) {
532 if (address_family == AF_UNIX)
return sock;
537 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on,
sizeof(on)) ==
SOCKET_ERROR) {
538 LogPrint(
BCLog::NET,
"Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n");
545 template<
typename... Args>
548 if (manual_connection) {
555 static bool ConnectToSocket(
const Sock& sock,
struct sockaddr* sockaddr, socklen_t len,
const std::string& dest_str,
bool manual_connection)
568 if (!sock.
Wait(std::chrono::milliseconds{nConnectTimeout}, requested, &occurred)) {
569 LogPrintf(
"wait for connect to %s failed: %s\n",
573 }
else if (occurred == 0) {
583 socklen_t sockerr_len =
sizeof(sockerr);
591 "connect() to %s failed after wait: %s",
619 struct sockaddr_storage sockaddr;
620 socklen_t len =
sizeof(sockaddr);
621 if (!dest.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
636 LogPrintf(
"Cannot connect to invalid Proxy\n");
651 struct sockaddr_un addrun;
652 memset(&addrun, 0,
sizeof(addrun));
653 addrun.sun_family = AF_UNIX;
655 memcpy(addrun.sun_path, path.c_str(), std::min(
sizeof(addrun.sun_path) - 1, path.length()));
656 socklen_t len =
sizeof(addrun);
658 if(!
ConnectToSocket(*sock, (
struct sockaddr*)&addrun, len, path,
true)) {
659 LogPrintf(
"Cannot connect to socket for %s\n", path);
674 proxyInfo[net] = addrProxy;
681 if (!proxyInfo[net].IsValid())
683 proxyInfoOut = proxyInfo[net];
691 nameProxy = addrProxy;
697 if(!nameProxy.IsValid())
699 nameProxyOut = nameProxy;
705 return nameProxy.IsValid();
710 for (
int i = 0; i <
NET_MAX; i++) {
711 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy))
718 const std::string& dest,
720 bool& proxy_connection_failed)
725 proxy_connection_failed =
true;
732 static std::atomic_int counter(0);
734 if (!
Socks5(dest, port, &random_auth, *sock)) {
738 if (!
Socks5(dest, port,
nullptr, *sock)) {
753 const size_t slash_pos{subnet_str.find_last_of(
'/')};
754 const std::string str_addr{subnet_str.substr(0, slash_pos)};
755 std::optional<CNetAddr> addr{
LookupHost(str_addr,
false)};
757 if (addr.has_value()) {
759 if (slash_pos != subnet_str.npos) {
760 const std::string netmask_str{subnet_str.substr(slash_pos + 1)};
764 subnet =
CSubNet{addr.value(), netmask};
767 const std::optional<CNetAddr> full_netmask{
LookupHost(netmask_str,
false)};
768 if (full_netmask.has_value()) {
769 subnet =
CSubNet{addr.value(), full_netmask.value()};
774 subnet =
CSubNet{addr.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
A helper class for interruptible sleeps.
Different type to mark Mutex at global scope.
bool m_randomize_credentials
std::unique_ptr< Sock > Connect() const
std::string m_unix_socket_path
List of reachable networks.
bool Contains(Network net) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
static constexpr Event SEND
If passed to Wait(), then it will wait for readiness to send to the socket.
virtual void SendComplete(Span< const unsigned char > data, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt) const
Send the given data, retrying on transient errors.
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 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.
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
SOCKS5Command
Values defined for CMD in RFC1928.
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 Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex)
std::chrono::milliseconds g_socks5_recv_timeout
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &... args)
std::string GetNetworkName(enum Network net)
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.
CThreadInterrupt g_socks5_interrupt
Interrupt SOCKS5 reads or writes.
SOCKSVersion
SOCKS version.
std::unique_ptr< Sock > CreateSockOS(sa_family_t address_family)
Create a TCP or UNIX socket in the given address family.
bool SetNameProxy(const Proxy &addrProxy)
Set the name proxy to use for all connections to nodes specified by a hostname.
enum Network ParseNetwork(const std::string &net_in)
static std::vector< CNetAddr > LookupIntern(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
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.
std::vector< CNetAddr > WrappedGetAddrInfo(const std::string &name, bool allow_lookup)
Wrapper for getaddrinfo(3).
static std::string Socks5ErrorString(uint8_t err)
Convert SOCKS5 reply to an error message.
bool SetProxy(enum Network net, const Proxy &addrProxy)
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.
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...
CService MaybeFlipIPv6toCJDNS(const CService &service)
If an IPv6 address belongs to the address range used by the CJDNS network and the CJDNS network is re...
static GlobalMutex g_proxyinfo_mutex
ReachableNets g_reachable_nets
bool GetProxy(enum Network net, Proxy &proxyInfoOut)
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::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 bool ConnectToSocket(const Sock &sock, struct sockaddr *sockaddr, socklen_t len, const std::string &dest_str, bool manual_connection)
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::function< std::unique_ptr< Sock >const sa_family_t &)> CreateSock
Socket factory.
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::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.
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.
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.