39 ai_hint.ai_socktype = SOCK_STREAM;
40 ai_hint.ai_protocol = IPPROTO_TCP;
42 ai_hint.ai_family = AF_UNSPEC;
49 ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
51 addrinfo* ai_res{
nullptr};
52 const int n_err{getaddrinfo(
name.c_str(),
nullptr, &ai_hint, &ai_res)};
58 addrinfo* ai_trav{ai_res};
59 std::vector<CNetAddr> resolved_addresses;
60 while (ai_trav !=
nullptr) {
61 if (ai_trav->ai_family == AF_INET) {
62 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in));
63 resolved_addresses.emplace_back(
reinterpret_cast<sockaddr_in*
>(ai_trav->ai_addr)->sin_addr);
65 if (ai_trav->ai_family == AF_INET6) {
66 assert(ai_trav->ai_addrlen >=
sizeof(sockaddr_in6));
67 const sockaddr_in6* s6{
reinterpret_cast<sockaddr_in6*
>(ai_trav->ai_addr)};
68 resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
70 ai_trav = ai_trav->ai_next;
74 return resolved_addresses;
80 std::string net =
ToLower(net_in);
85 LogPrintf(
"Warning: net name 'tor' is deprecated and will be removed in the future. You should use 'onion' instead.\n");
115 std::vector<std::string> names;
116 for (
int n = 0; n <
NET_MAX; ++n) {
121 if (append_unroutable) {
127 static std::vector<CNetAddr>
LookupIntern(
const std::string&
name,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
141 std::vector<CNetAddr> addresses;
143 for (
const CNetAddr& resolved : dns_lookup_function(
name, fAllowLookup)) {
144 if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {
148 if (!resolved.IsInternal()) {
149 addresses.push_back(resolved);
156 std::vector<CNetAddr>
LookupHost(
const std::string&
name,
unsigned int nMaxSolutions,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
159 std::string strHost =
name;
160 if (strHost.empty())
return {};
161 if (strHost.front() ==
'[' && strHost.back() ==
']') {
162 strHost = strHost.substr(1, strHost.size() - 2);
165 return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function);
170 const std::vector<CNetAddr> addresses{
LookupHost(
name, 1, fAllowLookup, dns_lookup_function)};
171 return addresses.empty() ? std::nullopt : std::make_optional(addresses.front());
174 std::vector<CService>
Lookup(
const std::string&
name, uint16_t portDefault,
bool fAllowLookup,
unsigned int nMaxSolutions,
DNSLookupFn dns_lookup_function)
179 uint16_t port{portDefault};
180 std::string hostname;
183 const std::vector<CNetAddr> addresses{
LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};
184 if (addresses.empty())
return {};
185 std::vector<CService> services;
186 services.reserve(addresses.size());
187 for (
const auto& addr : addresses)
188 services.emplace_back(addr, port);
192 std::optional<CService>
Lookup(
const std::string&
name, uint16_t portDefault,
bool fAllowLookup,
DNSLookupFn dns_lookup_function)
194 const std::vector<CService> services{
Lookup(
name, portDefault, fAllowLookup, 1, dns_lookup_function)};
196 return services.empty() ? std::nullopt : std::make_optional(services.front());
277 auto curTime{Now<SteadyMilliseconds>()};
278 const auto endTime{curTime + timeout};
279 while (len > 0 && curTime < endTime) {
280 ssize_t
ret = sock.
Recv(data, len, 0);
284 }
else if (
ret == 0) {
291 const auto remaining = std::chrono::milliseconds{endTime - curTime};
292 const auto timeout = std::min(remaining, std::chrono::milliseconds{
MAX_WAIT_FOR_IO});
302 curTime = Now<SteadyMilliseconds>();
312 return "general failure";
314 return "connection not allowed";
316 return "network unreachable";
318 return "host unreachable";
320 return "connection refused";
322 return "TTL expired";
324 return "protocol error";
326 return "address type not supported";
336 if (strDest.size() > 255) {
337 return error(
"Hostname too long");
340 std::vector<uint8_t> vSocks5Init;
343 vSocks5Init.push_back(0x02);
347 vSocks5Init.push_back(0x01);
351 if (
ret != (ssize_t)vSocks5Init.size()) {
352 return error(
"Error sending to proxy");
356 LogPrintf(
"Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
360 return error(
"Proxy failed to initialize");
364 std::vector<uint8_t> vAuth;
365 vAuth.push_back(0x01);
367 return error(
"Proxy username or password too long");
368 vAuth.push_back(auth->
username.size());
370 vAuth.push_back(auth->
password.size());
373 if (
ret != (ssize_t)vAuth.size()) {
374 return error(
"Error sending authentication to proxy");
379 return error(
"Error reading proxy authentication response");
381 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
382 return error(
"Proxy authentication unsuccessful");
387 return error(
"Proxy requested wrong authentication method %02x", pchRet1[1]);
389 std::vector<uint8_t> vSocks5;
392 vSocks5.push_back(0x00);
394 vSocks5.push_back(strDest.size());
395 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
396 vSocks5.push_back((port >> 8) & 0xFF);
397 vSocks5.push_back((port >> 0) & 0xFF);
399 if (
ret != (ssize_t)vSocks5.size()) {
400 return error(
"Error sending to proxy");
410 return error(
"Error while reading proxy response");
414 return error(
"Proxy failed to accept request");
421 if (pchRet2[2] != 0x00) {
422 return error(
"Error: malformed proxy response");
424 uint8_t pchRet3[256];
433 return error(
"Error reading from proxy");
435 int nRecv = pchRet3[0];
439 default:
return error(
"Error: malformed proxy response");
442 return error(
"Error reading from proxy");
445 return error(
"Error reading from proxy");
454 struct sockaddr_storage sockaddr;
455 socklen_t len =
sizeof(sockaddr);
456 if (!address_family.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
462 SOCKET hSocket = socket(((
struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
467 auto sock = std::make_unique<Sock>(hSocket);
471 if (!sock->IsSelectable()) {
472 LogPrintf(
"Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
480 if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, (
void*)&set,
sizeof(
int)) ==
SOCKET_ERROR) {
481 LogPrintf(
"Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",
488 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on,
sizeof(on)) ==
SOCKET_ERROR) {
489 LogPrint(
BCLog::NET,
"Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n");
493 if (!sock->SetNonBlocking()) {
502 template<
typename... Args>
505 if (manual_connection) {
515 struct sockaddr_storage sockaddr;
516 socklen_t len =
sizeof(sockaddr);
521 if (!addrConnect.
GetSockAddr((
struct sockaddr*)&sockaddr, &len)) {
537 if (!sock.
Wait(std::chrono::milliseconds{nTimeout}, requested, &occurred)) {
538 LogPrintf(
"wait for connect to %s failed: %s\n",
542 }
else if (occurred == 0) {
552 socklen_t sockerr_len =
sizeof(sockerr);
560 "connect() to %s failed after wait: %s",
584 proxyInfo[net] = addrProxy;
591 if (!proxyInfo[net].IsValid())
593 proxyInfoOut = proxyInfo[net];
601 nameProxy = addrProxy;
607 if(!nameProxy.IsValid())
609 nameProxyOut = nameProxy;
615 return nameProxy.IsValid();
620 for (
int i = 0; i <
NET_MAX; i++) {
621 if (addr ==
static_cast<CNetAddr>(proxyInfo[i].proxy))
627 bool ConnectThroughProxy(
const Proxy& proxy,
const std::string& strDest, uint16_t port,
const Sock& sock,
int nTimeout,
bool& outProxyConnectionFailed)
631 outProxyConnectionFailed =
true;
637 static std::atomic_int counter(0);
639 if (!
Socks5(strDest, port, &random_auth, sock)) {
643 if (!
Socks5(strDest, port,
nullptr, sock)) {
656 const size_t slash_pos{subnet_str.find_last_of(
'/')};
657 const std::string str_addr{subnet_str.substr(0, slash_pos)};
658 const std::optional<CNetAddr> addr{
LookupHost(str_addr,
false)};
660 if (addr.has_value()) {
661 if (slash_pos != subnet_str.npos) {
662 const std::string netmask_str{subnet_str.substr(slash_pos + 1)};
666 subnet_out =
CSubNet{addr.value(), netmask};
670 const std::optional<CNetAddr> full_netmask{
LookupHost(netmask_str,
false)};
671 if (full_netmask.has_value()) {
672 subnet_out =
CSubNet{addr.value(), full_netmask.value()};
678 subnet_out =
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.
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 randomize_credentials
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.
#define WSAGetLastError()
#define LogPrint(category,...)
bool error(const char *fmt, const Args &... args)
@ 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::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.
std::unique_ptr< Sock > CreateSockTCP(const CService &address_family)
Create a TCP socket in the given address family.
static std::atomic< bool > interruptSocks5Recv(false)
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.
SOCKSVersion
SOCKS version.
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).
bool LookupSubNet(const std::string &subnet_str, CSubNet &subnet_out)
Parse and resolve a specified subnet string into the appropriate internal representation.
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::function< std::unique_ptr< Sock >const CService &)> CreateSock
Socket factory.
bool ConnectThroughProxy(const Proxy &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...
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 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.
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.
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.
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.