PIVX Core  5.6.99
P2P Digital Currency
netbase.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 The Bitcoin developers
3 // Copyright (c) 2017-2022 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
6 
7 #include "netbase.h"
8 
9 #include "sync.h"
10 #include "random.h"
11 #include "tinyformat.h"
12 #include "util/string.h"
13 #include "util/system.h"
14 #include "utilstrencodings.h"
15 
16 #include <atomic>
17 #include <cstdint>
18 #include <limits>
19 
20 #ifndef WIN32
21 #include <fcntl.h>
22 #else
23 #include <codecvt>
24 #endif
25 
26 #ifdef USE_POLL
27 #include <poll.h>
28 #endif
29 
30 #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
31 #define MSG_NOSIGNAL 0
32 #endif
33 
34 
35 // Settings
36 static proxyType proxyInfo[NET_MAX];
37 static proxyType nameProxy;
38 static RecursiveMutex cs_proxyInfos;
39 int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
40 bool fNameLookup = false;
41 
42 // Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
43 static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
44 static std::atomic<bool> interruptSocks5Recv(false);
45 
46 enum Network ParseNetwork(std::string net)
47 {
48  Downcase(net);
49  if (net == "ipv4") return NET_IPV4;
50  if (net == "ipv6") return NET_IPV6;
51  if (net == "tor" || net == "onion") return NET_ONION;
52  return NET_UNROUTABLE;
53 }
54 
55 std::string GetNetworkName(enum Network net)
56 {
57  switch (net) {
58  case NET_UNROUTABLE: return "unroutable";
59  case NET_IPV4: return "ipv4";
60  case NET_IPV6: return "ipv6";
61  case NET_ONION: return "onion";
62  case NET_I2P: return "i2p";
63  case NET_CJDNS: return "cjdns";
64  case NET_INTERNAL: return "internal";
65  case NET_MAX: assert(false);
66  } // no default case, so the compiler can warn about missing cases
67 
68  assert(false);
69 }
70 
71 void SplitHostPort(std::string in, int& portOut, std::string& hostOut)
72 {
73  size_t colon = in.find_last_of(':');
74  // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
75  bool fHaveColon = colon != in.npos;
76  bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
77  bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos);
78  if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
79  int32_t n;
80  if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
81  in = in.substr(0, colon);
82  portOut = n;
83  }
84  }
85  if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']')
86  hostOut = in.substr(1, in.size() - 2);
87  else
88  hostOut = in;
89 }
90 
91 bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
92 {
93  vIP.clear();
94 
95  if (!ValidAsCString(name)) {
96  return false;
97  }
98 
99  {
100  CNetAddr addr;
101  if (addr.SetSpecial(name)) {
102  vIP.push_back(addr);
103  return true;
104  }
105  }
106 
107  struct addrinfo aiHint;
108  memset(&aiHint, 0, sizeof(struct addrinfo));
109 
110  aiHint.ai_socktype = SOCK_STREAM;
111  aiHint.ai_protocol = IPPROTO_TCP;
112  aiHint.ai_family = AF_UNSPEC;
113 #ifdef WIN32
114  aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
115 #else
116  aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
117 #endif
118  struct addrinfo* aiRes = nullptr;
119  int nErr = getaddrinfo(name.c_str(), nullptr, &aiHint, &aiRes);
120  if (nErr)
121  return false;
122 
123  struct addrinfo* aiTrav = aiRes;
124  while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) {
125  CNetAddr resolved;
126  if (aiTrav->ai_family == AF_INET) {
127  assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
128  resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
129  }
130 
131  if (aiTrav->ai_family == AF_INET6) {
132  assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
133  struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
134  resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
135  }
136  /* Never allow resolving to an internal address. Consider any such result invalid */
137  if (!resolved.IsInternal()) {
138  vIP.push_back(resolved);
139  }
140 
141  aiTrav = aiTrav->ai_next;
142  }
143 
144  freeaddrinfo(aiRes);
145 
146  return (vIP.size() > 0);
147 }
148 
149 bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
150 {
151  if (!ValidAsCString(name)) {
152  return false;
153  }
154  std::string strHost = name;
155  if (strHost.empty())
156  return false;
157  if (strHost.front() == '[' && strHost.back() == ']') {
158  strHost = strHost.substr(1, strHost.size() - 2);
159  }
160 
161  return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup);
162 }
163 
164 bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup)
165 {
166  if (!ValidAsCString(name)) {
167  return false;
168  }
169  std::vector<CNetAddr> vIP;
170  LookupHost(name, vIP, 1, fAllowLookup);
171  if (vIP.empty())
172  return false;
173  addr = vIP.front();
174  return true;
175 }
176 
177 bool Lookup(const std::string& name, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
178 {
179  if (name.empty() || !ValidAsCString(name)) {
180  return false;
181  }
182  int port = portDefault;
183  std::string hostname;
184  SplitHostPort(name, port, hostname);
185 
186  std::vector<CNetAddr> vIP;
187  bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup);
188  if (!fRet)
189  return false;
190  vAddr.resize(vIP.size());
191  for (unsigned int i = 0; i < vIP.size(); i++)
192  vAddr[i] = CService(vIP[i], port);
193  return true;
194 }
195 
196 bool Lookup(const std::string& name, CService& addr, int portDefault, bool fAllowLookup)
197 {
198  if (!ValidAsCString(name)) {
199  return false;
200  }
201  std::vector<CService> vService;
202  bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1);
203  if (!fRet)
204  return false;
205  addr = vService[0];
206  return true;
207 }
208 
209 CService LookupNumeric(const std::string& name, int portDefault)
210 {
211  if (!ValidAsCString(name)) {
212  return {};
213  }
214  CService addr;
215  // "1.2:345" will fail to resolve the ip, but will still set the port.
216  // If the ip fails to resolve, re-init the result.
217  if (!Lookup(name, addr, portDefault, false))
218  addr = CService();
219  return addr;
220 }
221 
222 struct timeval MillisToTimeval(int64_t nTimeout)
223 {
224  struct timeval timeout;
225  timeout.tv_sec = nTimeout / 1000;
226  timeout.tv_usec = (nTimeout % 1000) * 1000;
227  return timeout;
228 }
229 
231 enum SOCKSVersion: uint8_t {
232  SOCKS4 = 0x04,
233  SOCKS5 = 0x05
234 };
235 
237 enum SOCKS5Method: uint8_t {
238  NOAUTH = 0x00,
239  GSSAPI = 0x01,
240  USER_PASS = 0x02,
241  NO_ACCEPTABLE = 0xff,
242 };
243 
245 enum SOCKS5Command: uint8_t {
246  CONNECT = 0x01,
247  BIND = 0x02,
248  UDP_ASSOCIATE = 0x03
249 };
250 
252 enum SOCKS5Reply: uint8_t {
253  SUCCEEDED = 0x00,
254  GENFAILURE = 0x01,
255  NOTALLOWED = 0x02,
256  NETUNREACHABLE = 0x03,
258  CONNREFUSED = 0x05,
259  TTLEXPIRED = 0x06,
260  CMDUNSUPPORTED = 0x07,
262 };
263 
265 enum SOCKS5Atyp: uint8_t {
266  IPV4 = 0x01,
267  DOMAINNAME = 0x03,
268  IPV6 = 0x04,
269 };
270 
272 enum class IntrRecvError {
273  OK,
274  Timeout,
275  Disconnected,
276  NetworkError,
278 };
279 
291 static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
292 {
293  int64_t curTime = GetTimeMillis();
294  int64_t endTime = curTime + timeout;
295  // Maximum time to wait in one select call. It will take up until this time (in millis)
296  // to break off in case of an interruption.
297  const int64_t maxWait = 1000;
298  while (len > 0 && curTime < endTime) {
299  ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
300  if (ret > 0) {
301  len -= ret;
302  data += ret;
303  } else if (ret == 0) { // Unexpected disconnection
305  } else { // Other error or blocking
306  int nErr = WSAGetLastError();
307  if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
308  if (!IsSelectableSocket(hSocket)) {
310  }
311  int timeout_ms = std::min(endTime - curTime, maxWait);
312 #ifdef USE_POLL
313  struct pollfd pollfd = {};
314  pollfd.fd = hSocket;
315  pollfd.events = POLLIN | POLLOUT;
316  int nRet = poll(&pollfd, 1, timeout_ms);
317 #else
318  struct timeval tval = MillisToTimeval(timeout_ms);
319  fd_set fdset;
320  FD_ZERO(&fdset);
321  FD_SET(hSocket, &fdset);
322  int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
323 #endif
324  if (nRet == SOCKET_ERROR) {
326  }
327  } else {
329  }
330  }
331  if (interruptSocks5Recv)
333  curTime = GetTimeMillis();
334  }
335  return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
336 }
337 
340 {
341  std::string username;
342  std::string password;
343 };
344 
346 static std::string Socks5ErrorString(uint8_t err)
347 {
348  switch(err) {
350  return "general failure";
352  return "connection not allowed";
354  return "network unreachable";
356  return "host unreachable";
358  return "connection refused";
360  return "TTL expired";
362  return "protocol error";
364  return "address type not supported";
365  default:
366  return "unknown";
367  }
368 }
369 
371 bool static Socks5(std::string strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
372 {
373  IntrRecvError recvr;
374  LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
375  if (strDest.size() > 255) {
376  return error("Hostname too long");
377  }
378  // Accepted authentication methods
379  std::vector<uint8_t> vSocks5Init;
380  vSocks5Init.push_back(SOCKSVersion::SOCKS5);
381  if (auth) {
382  vSocks5Init.push_back(0x02); // Number of methods
383  vSocks5Init.push_back(SOCKS5Method::NOAUTH);
384  vSocks5Init.push_back(SOCKS5Method::USER_PASS);
385  } else {
386  vSocks5Init.push_back(0x01); // Number of methods
387  vSocks5Init.push_back(SOCKS5Method::NOAUTH);
388  }
389  ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
390  if (ret != (ssize_t)vSocks5Init.size()) {
391  return error("Error sending to proxy");
392  }
393  uint8_t pchRet1[2];
394  if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
395  LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
396  return false;
397  }
398  if (pchRet1[0] != SOCKSVersion::SOCKS5) {
399  return error("Proxy failed to initialize");
400  }
401  if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
402  // Perform username/password authentication (as described in RFC1929)
403  std::vector<uint8_t> vAuth;
404  vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
405  if (auth->username.size() > 255 || auth->password.size() > 255)
406  return error("Proxy username or password too long");
407  vAuth.push_back(auth->username.size());
408  vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
409  vAuth.push_back(auth->password.size());
410  vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
411  ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
412  if (ret != (ssize_t)vAuth.size()) {
413  return error("Error sending authentication to proxy");
414  }
415  LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
416  uint8_t pchRetA[2];
417  if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
418  return error("Error reading proxy authentication response");
419  }
420  if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
421  return error("Proxy authentication unsuccessful");
422  }
423  } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
424  // Perform no authentication
425  } else {
426  return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
427  }
428  std::vector<uint8_t> vSocks5;
429  vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
430  vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
431  vSocks5.push_back(0x00); // RSV Reserved must be 0
432  vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
433  vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
434  vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
435  vSocks5.push_back((port >> 8) & 0xFF);
436  vSocks5.push_back((port >> 0) & 0xFF);
437  ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
438  if (ret != (ssize_t)vSocks5.size()) {
439  return error("Error sending to proxy");
440  }
441  uint8_t pchRet2[4];
442  if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
443  if (recvr == IntrRecvError::Timeout) {
444  /* If a timeout happens here, this effectively means we timed out while connecting
445  * to the remote node. This is very common for Tor, so do not print an
446  * error message. */
447  return false;
448  } else {
449  return error("Error while reading proxy response");
450  }
451  }
452  if (pchRet2[0] != SOCKSVersion::SOCKS5) {
453  return error("Proxy failed to accept request");
454  }
455  if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
456  // Failures to connect to a peer that are not proxy errors
457  LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
458  return false;
459  }
460  if (pchRet2[2] != 0x00) { // Reserved field must be 0
461  return error("Error: malformed proxy response");
462  }
463  uint8_t pchRet3[256];
464  switch (pchRet2[3])
465  {
466  case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
467  case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
469  {
470  recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
471  if (recvr != IntrRecvError::OK) {
472  return error("Error reading from proxy");
473  }
474  int nRecv = pchRet3[0];
475  recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
476  break;
477  }
478  default: return error("Error: malformed proxy response");
479  }
480  if (recvr != IntrRecvError::OK) {
481  return error("Error reading from proxy");
482  }
483  if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
484  return error("Error reading from proxy");
485  }
486  LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
487  return true;
488 }
489 
490 SOCKET CreateSocket(const CService& addrConnect)
491 {
492  struct sockaddr_storage sockaddr;
493  socklen_t len = sizeof(sockaddr);
494  if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
495  LogPrintf("Cannot create socket for %s: unsupported network\n", addrConnect.ToString());
496  return INVALID_SOCKET;
497  }
498 
499  SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
500  if (hSocket == INVALID_SOCKET)
501  return INVALID_SOCKET;
502 
503  if (!IsSelectableSocket(hSocket)) {
504  CloseSocket(hSocket);
505  LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
506  return INVALID_SOCKET;
507  }
508 
509 #ifdef SO_NOSIGPIPE
510  int set = 1;
511  // Different way of disabling SIGPIPE on BSD
512  setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
513 #endif
514  // Disable Nagle's algorithm
515  SetSocketNoDelay(hSocket);
516 
517  // Set to non-blocking
518  if (!SetSocketNonBlocking(hSocket, true)) {
519  CloseSocket(hSocket);
520  LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
521  }
522  return hSocket;
523 }
524 
525 template<typename... Args>
526 static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) {
527  std::string error_message = tfm::format(fmt, args...);
528  if (manual_connection) {
529  LogPrintf("%s\n", error_message);
530  } else {
531  LogPrint(BCLog::NET, "%s\n", error_message);
532  }
533 }
534 
535 bool ConnectSocketDirectly(const CService& addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
536 {
537  struct sockaddr_storage sockaddr;
538  socklen_t len = sizeof(sockaddr);
539  if (hSocket == INVALID_SOCKET) {
540  LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToString());
541  return false;
542  }
543  if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
544  LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
545  return false;
546  }
547  if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) {
548  int nErr = WSAGetLastError();
549  // WSAEINVAL is here because some legacy version of winsock uses it
550  if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
551 #ifdef USE_POLL
552  struct pollfd pollfd = {};
553  pollfd.fd = hSocket;
554  pollfd.events = POLLIN | POLLOUT;
555  int nRet = poll(&pollfd, 1, nTimeout);
556 #else
557  struct timeval timeout = MillisToTimeval(nTimeout);
558  fd_set fdset;
559  FD_ZERO(&fdset);
560  FD_SET(hSocket, &fdset);
561  int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
562 #endif
563  if (nRet == 0) {
564  LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
565  return false;
566  }
567  if (nRet == SOCKET_ERROR) {
568  LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
569  return false;
570  }
571  socklen_t nRetSize = sizeof(nRet);
572  if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
573  {
574  LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
575  return false;
576  }
577  if (nRet != 0) {
578  LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet));
579  return false;
580  }
581  }
582 #ifdef WIN32
583  else if (WSAGetLastError() != WSAEISCONN)
584 #else
585  else
586 #endif
587  {
588  LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
589  return false;
590  }
591  }
592  return true;
593 }
594 
595 bool SetProxy(enum Network net, const proxyType &addrProxy)
596 {
597  assert(net >= 0 && net < NET_MAX);
598  if (!addrProxy.IsValid())
599  return false;
600  LOCK(cs_proxyInfos);
601  proxyInfo[net] = addrProxy;
602  return true;
603 }
604 
605 bool GetProxy(enum Network net, proxyType& proxyInfoOut)
606 {
607  assert(net >= 0 && net < NET_MAX);
608  LOCK(cs_proxyInfos);
609  if (!proxyInfo[net].IsValid())
610  return false;
611  proxyInfoOut = proxyInfo[net];
612  return true;
613 }
614 
615 bool SetNameProxy(const proxyType &addrProxy)
616 {
617  if (!addrProxy.IsValid())
618  return false;
619  LOCK(cs_proxyInfos);
620  nameProxy = addrProxy;
621  return true;
622 }
623 
624 bool GetNameProxy(proxyType &nameProxyOut)
625 {
626  LOCK(cs_proxyInfos);
627  if (!nameProxy.IsValid())
628  return false;
629  nameProxyOut = nameProxy;
630  return true;
631 }
632 
634 {
635  LOCK(cs_proxyInfos);
636  return nameProxy.IsValid();
637 }
638 
639 bool IsProxy(const CNetAddr& addr)
640 {
641  LOCK(cs_proxyInfos);
642  for (int i = 0; i < NET_MAX; i++) {
643  if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy))
644  return true;
645  }
646  return false;
647 }
648 
649 bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
650 {
651  // first connect to proxy server
652  if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) {
653  if (outProxyConnectionFailed)
654  *outProxyConnectionFailed = true;
655  return false;
656  }
657  // do socks negotiation
658  if (proxy.randomize_credentials) {
659  ProxyCredentials random_auth;
660  static std::atomic_int counter;
661  random_auth.username = random_auth.password = strprintf("%i", counter++);
662  if (!Socks5(strDest, (uint16_t)port, &random_auth, hSocket)) {
663  return false;
664  }
665  } else {
666  if (!Socks5(strDest, (uint16_t)port, 0, hSocket)) {
667  return false;
668  }
669  }
670  return true;
671 }
672 
673 bool LookupSubNet(const std::string& strSubnet, CSubNet& ret)
674 {
675  if (!ValidAsCString(strSubnet)) {
676  return false;
677  }
678  size_t slash = strSubnet.find_last_of('/');
679  std::vector<CNetAddr> vIP;
680 
681  std::string strAddress = strSubnet.substr(0, slash);
682  if (LookupHost(strAddress, vIP, 1, false))
683  {
684  CNetAddr network = vIP[0];
685  if (slash != strSubnet.npos) {
686  std::string strNetmask = strSubnet.substr(slash + 1);
687  uint8_t n;
688  if (ParseUInt8(strNetmask, &n)) {
689  // If valid number, assume CIDR variable-length subnet masking
690  ret = CSubNet(network, n);
691  return ret.IsValid();
692  } else // If not a valid number, try full netmask syntax
693  {
694  // Never allow lookup for netmask
695  if (LookupHost(strNetmask, vIP, 1, false)) {
696  ret = CSubNet(network, vIP[0]);
697  return ret.IsValid();
698  }
699  }
700  } else {
701  ret = CSubNet(network);
702  return ret.IsValid();
703  }
704  }
705  return false;
706 }
707 
708 #ifdef WIN32
709 std::string NetworkErrorString(int err)
710 {
711  wchar_t buf[256];
712  buf[0] = 0;
713  if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
714  nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
715  buf, ARRAYSIZE(buf), nullptr))
716  {
717  const auto& bufConvert = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf);
718  return strprintf("%s (%d)", bufConvert, err);
719  } else {
720  return strprintf("Unknown error (%d)", err);
721  }
722 }
723 #else
724 std::string NetworkErrorString(int err)
725 {
726  char buf[256];
727  buf[0] = 0;
728 /* Too bad there are two incompatible implementations of the
729  * thread-safe strerror. */
730  const char *s;
731 #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
732  s = strerror_r(err, buf, sizeof(buf));
733 #else /* POSIX variant always returns message in buffer */
734  s = buf;
735  if (strerror_r(err, buf, sizeof(buf)))
736  buf[0] = 0;
737 #endif
738  return strprintf("%s (%d)", s, err);
739 }
740 #endif
741 
742 bool CloseSocket(SOCKET& hSocket)
743 {
744  if (hSocket == INVALID_SOCKET)
745  return false;
746 #ifdef WIN32
747  int ret = closesocket(hSocket);
748 #else
749  int ret = close(hSocket);
750 #endif
751  hSocket = INVALID_SOCKET;
752  return ret != SOCKET_ERROR;
753 }
754 
755 bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
756 {
757  if (fNonBlocking) {
758 #ifdef WIN32
759  u_long nOne = 1;
760  if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
761 #else
762  int fFlags = fcntl(hSocket, F_GETFL, 0);
763  if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
764 #endif
765  CloseSocket(hSocket);
766  return false;
767  }
768  } else {
769 #ifdef WIN32
770  u_long nZero = 0;
771  if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
772 #else
773  int fFlags = fcntl(hSocket, F_GETFL, 0);
774  if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
775 #endif
776  CloseSocket(hSocket);
777  return false;
778  }
779  }
780 
781  return true;
782 }
783 
784 bool SetSocketNoDelay(SOCKET& hSocket)
785 {
786  int set = 1;
787  int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
788  return rc == 0;
789 }
790 
791 void InterruptSocks5(bool interrupt)
792 {
793  interruptSocks5Recv = interrupt;
794 }
Network address.
Definition: netaddress.h:120
bool SetSpecial(const std::string &strName)
Parse a TOR address and set this object to it.
Definition: netaddress.cpp:231
bool IsInternal() const
Definition: netaddress.cpp:464
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:484
std::string ToString() const
Definition: netaddress.cpp:954
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Definition: netaddress.cpp:902
bool IsValid() const
bool IsValid() const
Definition: netbase.h:35
CService proxy
Definition: netbase.h:37
bool randomize_credentials
Definition: netbase.h:38
#define INVALID_SOCKET
Definition: compat.h:64
u_int SOCKET
Definition: compat.h:53
#define WSAEWOULDBLOCK
Definition: compat.h:58
#define WSAEINVAL
Definition: compat.h:56
#define SOCKET_ERROR
Definition: compat.h:65
#define WSAGetLastError()
Definition: compat.h:55
#define MSG_NOSIGNAL
Definition: compat.h:79
void * sockopt_arg_type
Definition: compat.h:98
#define WSAEINPROGRESS
Definition: compat.h:61
@ LOCK
Definition: lockunlock.h:16
#define LogPrint(category,...)
Definition: logging.h:163
@ PROXY
Definition: logging.h:52
@ NET
Definition: logging.h:41
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:958
Network
A network type.
Definition: netaddress.h:44
@ NET_I2P
I2P.
Definition: netaddress.h:58
@ NET_CJDNS
CJDNS.
Definition: netaddress.h:61
@ NET_MAX
Dummy value to indicate the number of NET_* constants.
Definition: netaddress.h:68
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:55
@ NET_IPV6
IPv6.
Definition: netaddress.h:52
@ NET_IPV4
IPv4.
Definition: netaddress.h:49
@ NET_UNROUTABLE
Addresses from these networks are not publicly routable on the global Internet.
Definition: netaddress.h:46
@ NET_INTERNAL
A set of addresses that represent the hash of a string or FQDN.
Definition: netaddress.h:65
IntrRecvError
Status codes that can be returned by InterruptibleRecv.
Definition: netbase.cpp:272
SOCKS5Atyp
Values defined for ATYPE in RFC1928.
Definition: netbase.cpp:265
@ DOMAINNAME
Definition: netbase.cpp:267
@ IPV4
Definition: netbase.cpp:266
@ IPV6
Definition: netbase.cpp:268
SOCKS5Command
Values defined for CMD in RFC1928.
Definition: netbase.cpp:245
@ UDP_ASSOCIATE
Definition: netbase.cpp:248
@ CONNECT
Definition: netbase.cpp:246
@ BIND
Definition: netbase.cpp:247
struct timeval MillisToTimeval(int64_t nTimeout)
Convert milliseconds to a struct timeval for e.g.
Definition: netbase.cpp:222
bool GetNameProxy(proxyType &nameProxyOut)
Definition: netbase.cpp:624
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)
Definition: netbase.cpp:71
bool SetSocketNoDelay(SOCKET &hSocket)
Set the TCP_NODELAY flag on a socket.
Definition: netbase.cpp:784
enum Network ParseNetwork(std::string net)
Definition: netbase.cpp:46
std::string GetNetworkName(enum Network net)
Definition: netbase.cpp:55
SOCKSVersion
SOCKS version.
Definition: netbase.cpp:231
@ SOCKS4
Definition: netbase.cpp:232
@ SOCKS5
Definition: netbase.cpp:233
bool HaveNameProxy()
Definition: netbase.cpp:633
bool GetProxy(enum Network net, proxyType &proxyInfoOut)
Definition: netbase.cpp:605
bool Lookup(const std::string &name, std::vector< CService > &vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
Definition: netbase.cpp:177
CService LookupNumeric(const std::string &name, int portDefault)
Definition: netbase.cpp:209
bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest, int port, const SOCKET &hSocket, int nTimeout, bool *outProxyConnectionFailed)
Definition: netbase.cpp:649
bool SetSocketNonBlocking(SOCKET &hSocket, bool fNonBlocking)
Disable or enable blocking-mode for a socket.
Definition: netbase.cpp:755
SOCKS5Method
Values defined for METHOD in RFC1928.
Definition: netbase.cpp:237
@ GSSAPI
No authentication required.
Definition: netbase.cpp:239
@ NOAUTH
Definition: netbase.cpp:238
@ USER_PASS
GSSAPI.
Definition: netbase.cpp:240
@ NO_ACCEPTABLE
Username/password.
Definition: netbase.cpp:241
void InterruptSocks5(bool interrupt)
Definition: netbase.cpp:791
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition: netbase.cpp:724
SOCKS5Reply
Values defined for REP in RFC1928.
Definition: netbase.cpp:252
@ TTLEXPIRED
Connection refused.
Definition: netbase.cpp:259
@ CMDUNSUPPORTED
TTL expired.
Definition: netbase.cpp:260
@ NETUNREACHABLE
Connection not allowed by ruleset.
Definition: netbase.cpp:256
@ GENFAILURE
Succeeded.
Definition: netbase.cpp:254
@ CONNREFUSED
Network unreachable.
Definition: netbase.cpp:258
@ SUCCEEDED
Definition: netbase.cpp:253
@ ATYPEUNSUPPORTED
Command not supported.
Definition: netbase.cpp:261
@ NOTALLOWED
General failure.
Definition: netbase.cpp:255
@ HOSTUNREACHABLE
Network unreachable.
Definition: netbase.cpp:257
bool LookupHost(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup)
Definition: netbase.cpp:149
bool fNameLookup
Definition: netbase.cpp:40
bool LookupSubNet(const std::string &strSubnet, CSubNet &ret)
Definition: netbase.cpp:673
int nConnectTimeout
Definition: netbase.cpp:39
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET &hSocket, int nTimeout, bool manual_connection)
Definition: netbase.cpp:535
bool SetNameProxy(const proxyType &addrProxy)
Definition: netbase.cpp:615
bool CloseSocket(SOCKET &hSocket)
Close socket and set hSocket to INVALID_SOCKET.
Definition: netbase.cpp:742
bool IsProxy(const CNetAddr &addr)
Definition: netbase.cpp:639
SOCKET CreateSocket(const CService &addrConnect)
Definition: netbase.cpp:490
bool SetProxy(enum Network net, const proxyType &addrProxy)
Definition: netbase.cpp:595
const char * name
Definition: rest.cpp:37
bool ValidAsCString(const std::string &str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Definition: string.h:44
Credentials for proxy authentication.
Definition: netbase.cpp:340
std::string username
Definition: netbase.cpp:341
std::string password
Definition: netbase.cpp:342
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
#define strprintf
Definition: tinyformat.h:1056
void Downcase(std::string &str)
Converts the given string to its lowercase equivalent.
bool ParseInt32(const std::string &str, int32_t *out)
Convert string to signed 32-bit integer with strict parse error feedback.
bool ParseUInt8(const std::string &str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:61