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(
74 reinterpret_cast<sockaddr_in *
>(ai_trav->ai_addr)->sin_addr);
76 if (ai_trav->ai_family == AF_INET6) {
77 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
78 const sockaddr_in6 *s6{
79 reinterpret_cast<sockaddr_in6 *
>(ai_trav->ai_addr)};
80 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
82 ai_trav = ai_trav->ai_next;
86 return resolved_addresses;
92 std::string net =
ToLower(net_in);
103 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed "
104 "in the future. You should use 'onion' instead.\n");
116 return "not_publicly_routable";
137 std::vector<std::string> names;
138 for (
int n = 0; n <
NET_MAX; ++n) {
146 if (append_unroutable) {
153 unsigned int nMaxSolutions,
bool fAllowLookup,
175 for (
const CNetAddr &resolved : dns_lookup_function(
name, fAllowLookup)) {
176 if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
182 if (!resolved.IsInternal()) {
183 vIP.push_back(resolved);
187 return (vIP.size() > 0);
191 unsigned int nMaxSolutions,
bool fAllowLookup,
196 std::string strHost =
name;
197 if (strHost.empty()) {
200 if (strHost.front() ==
'[' && strHost.back() ==
']') {
201 strHost = strHost.substr(1, strHost.size() - 2);
204 return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup,
205 dns_lookup_function);
213 std::vector<CNetAddr> vIP;
222 bool Lookup(
const std::string &
name, std::vector<CService> &vAddr,
223 uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
228 uint16_t port{portDefault};
229 std::string hostname;
232 std::vector<CNetAddr> vIP;
233 bool fRet =
LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup,
234 dns_lookup_function);
238 vAddr.resize(vIP.size());
239 for (
unsigned int i = 0; i < vIP.size(); i++) {
246 bool fAllowLookup,
DNSLookupFn dns_lookup_function) {
250 std::vector<CService> vService;
251 bool fRet =
Lookup(
name, vService, portDefault, fAllowLookup, 1,
252 dns_lookup_function);
268 if (!
Lookup(
name, addr, portDefault,
false, dns_lookup_function)) {
342 int64_t endTime = curTime + timeout;
343 while (len > 0 && curTime < endTime) {
345 ssize_t ret = sock.
Recv(data, len, 0);
349 }
else if (ret == 0) {
359 const auto remaining =
360 std::chrono::milliseconds{endTime - curTime};
361 const auto timeout_ = std::min(
388 return "general failure";
390 return "connection not allowed";
392 return "network unreachable";
394 return "host unreachable";
396 return "connection refused";
398 return "TTL expired";
400 return "protocol error";
402 return "address type not supported";
426 static bool Socks5(
const std::string &strDest, uint16_t port,
430 if (strDest.size() > 255) {
431 return error(
"Hostname too long");
434 std::vector<uint8_t> vSocks5Init;
439 vSocks5Init.push_back(0x02);
444 vSocks5Init.push_back(0x01);
449 if (ret != (ssize_t)vSocks5Init.size()) {
450 return error(
"Error sending to proxy");
455 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() "
456 "timeout or other failure\n",
461 return error(
"Proxy failed to initialize");
465 std::vector<uint8_t> vAuth;
467 vAuth.push_back(0x01);
469 return error(
"Proxy username or password too long");
471 vAuth.push_back(auth->
username.size());
473 vAuth.push_back(auth->
password.size());
476 if (ret != (ssize_t)vAuth.size()) {
477 return error(
"Error sending authentication to proxy");
484 return error(
"Error reading proxy authentication response");
486 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
487 return error(
"Proxy authentication unsuccessful");
492 return error(
"Proxy requested wrong authentication method %02x",
495 std::vector<uint8_t> vSocks5;
501 vSocks5.push_back(0x00);
505 vSocks5.push_back(strDest.size());
506 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
507 vSocks5.push_back((port >> 8) & 0xFF);
508 vSocks5.push_back((port >> 0) & 0xFF);
510 if (ret != (ssize_t)vSocks5.size()) {
511 return error(
"Error sending to proxy");
524 return error(
"Error while reading proxy response");
528 return error(
"Proxy failed to accept request");
532 LogPrintf(
"Socks5() connect to %s:%d failed: %s\n", strDest, port,
537 if (pchRet2[2] != 0x00) {
538 return error(
"Error: malformed proxy response");
540 uint8_t pchRet3[256];
541 switch (pchRet2[3]) {
551 return error(
"Error reading from proxy");
553 int nRecv = pchRet3[0];
559 return error(
"Error: malformed proxy response");
562 return error(
"Error reading from proxy");
566 return error(
"Error reading from proxy");
574 struct sockaddr_storage sockaddr;
575 socklen_t len =
sizeof(sockaddr);
576 if (!address_family.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
577 LogPrintf(
"Cannot create socket for %s: unsupported network\n",
583 SOCKET hSocket = socket(((
struct sockaddr *)&sockaddr)->sa_family,
584 SOCK_STREAM, IPPROTO_TCP);
593 LogPrintf(
"Cannot create connection: non-selectable socket created (fd "
594 ">= FD_SETSIZE ?)\n");
612 LogPrintf(
"CreateSocket: Setting socket to non-blocking "
613 "failed, error %s\n",
617 return std::make_unique<Sock>(hSocket);
623 template <
typename... Args>
625 const Args &...args) {
626 std::string error_message =
tfm::format(fmt, args...);
627 if (manual_connection) {
635 int nTimeout,
bool manual_connection) {
637 struct sockaddr_storage sockaddr;
638 socklen_t len =
sizeof(sockaddr);
640 LogPrintf(
"Cannot connect to %s: invalid socket\n",
644 if (!addrConnect.
GetSockAddr((
struct sockaddr *)&sockaddr, &len)) {
645 LogPrintf(
"Cannot connect to %s: unsupported network\n",
651 if (sock.
Connect(
reinterpret_cast<struct sockaddr *
>(&sockaddr), len) ==
662 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested,
664 LogPrintf(
"wait for connect to %s failed: %s\n",
668 }
else if (occurred == 0) {
679 socklen_t sockerr_len =
sizeof(sockerr);
683 LogPrintf(
"getsockopt() for %s failed: %s\n",
690 manual_connection,
"connect() to %s failed after wait: %s",
716 proxyInfo[net] = addrProxy;
723 if (!proxyInfo[net].IsValid()) {
726 proxyInfoOut = proxyInfo[net];
735 nameProxy = addrProxy;
741 if (!nameProxy.IsValid()) {
744 nameProxyOut = nameProxy;
750 return nameProxy.IsValid();
755 for (
int i = 0; i <
NET_MAX; i++) {
756 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy)) {
764 uint16_t port,
const Sock &sock,
int nTimeout,
765 bool &outProxyConnectionFailed) {
768 outProxyConnectionFailed =
true;
774 static std::atomic_int counter(0);
777 if (!
Socks5(strDest, port, &random_auth, sock)) {
780 }
else if (!
Socks5(strDest, port, 0, sock)) {
791 size_t slash = strSubnet.find_last_of(
'/');
792 std::vector<CNetAddr> vIP;
794 std::string strAddress = strSubnet.substr(0, slash);
796 if (
LookupHost(strAddress, vIP, 1,
false, dns_lookup_function)) {
798 if (slash != strSubnet.npos) {
799 std::string strNetmask = strSubnet.substr(slash + 1);
809 dns_lookup_function)) {
810 ret =
CSubNet(network, vIP[0]);
826 if (ioctlsocket(hSocket, FIONBIO, &nOne) ==
SOCKET_ERROR) {
828 int fFlags = fcntl(hSocket, F_GETFL, 0);
829 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) ==
SOCKET_ERROR) {
836 if (ioctlsocket(hSocket, FIONBIO, &nZero) ==
SOCKET_ERROR) {
838 int fFlags = fcntl(hSocket, F_GETFL, 0);
839 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) ==
SOCKET_ERROR) {
850 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)
#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::unique_ptr< Sock > CreateSockTCP(const CService &address_family)
Create a TCP socket in the given address family.
static std::atomic< bool > interruptSocks5Recv(false)
std::string GetNetworkName(enum Network net)
static void LogConnectFailure(bool manual_connection, const char *fmt, const Args &...args)
SOCKSVersion
SOCKS version.
static 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.
bool GetProxy(enum Network net, proxyType &proxyInfoOut)
static const int SOCKS5_RECV_TIMEOUT
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.
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.
void InterruptSocks5(bool interrupt)
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
std::function< std::unique_ptr< Sock >const CService &)> CreateSock
Socket factory.
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 proxyType proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex)
std::vector< std::string > GetNetworkNames(bool append_unroutable)
Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE.
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.
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)
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.
std::string ToLower(const std::string &str)
Returns the lowercase equivalent of the given string.
void SplitHostPort(std::string in, uint16_t &portOut, std::string &hostOut)
bool ParseUInt8(const std::string &str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
bool ValidAsCString(const std::string &str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Credentials for proxy authentication.
bool error(const char *fmt, const Args &...args)
int64_t GetTimeMillis()
Returns the system time (not mockable)