Electroneum
tools::dns_utils Namespace Reference

Functions

std::string address_from_txt_record (const std::string &s)
 
std::vector< std::string > addresses_from_url (const std::string &url, bool &dnssec_valid)
 gets a electroneum address from the TXT record of a DNS entry More...
 
std::string get_account_address_as_str_from_url (const std::string &url, bool &dnssec_valid, std::function< std::string(const std::string &, const std::vector< std::string > &, bool)> dns_confirm)
 
bool load_txt_records_from_dns (std::vector< std::string > &good_records, const std::vector< std::string > &dns_urls, std::string type)
 
std::vector< std::string > parse_dns_public (const char *s)
 

Function Documentation

◆ address_from_txt_record()

std::string tools::dns_utils::address_from_txt_record ( const std::string &  s)

Definition at line 411 of file dns_utils.cpp.

412 {
413  // make sure the txt record has "oa1:etn" and find it
414  auto pos = s.find("oa1:etn");
415  if (pos == std::string::npos)
416  return {};
417  // search from there to find "recipient_address="
418  pos = s.find("recipient_address=", pos);
419  if (pos == std::string::npos)
420  return {};
421  pos += 18; // move past "recipient_address="
422  // find the next semicolon
423  auto pos2 = s.find(";", pos);
424  if (pos2 != std::string::npos)
425  {
426  // length of address == 98, we can at least validate that much here
427  if (pos2 - pos == 98)
428  {
429  return s.substr(pos, 98);
430  }
431  else if (pos2 - pos == 109) // length of address == 109 --> integrated address
432  {
433  return s.substr(pos, 109);
434  }
435  }
436  return {};
437 }
Here is the caller graph for this function:

◆ addresses_from_url()

std::vector< std::string > tools::dns_utils::addresses_from_url ( const std::string &  url,
bool dnssec_valid 
)

gets a electroneum address from the TXT record of a DNS entry

gets the electroneum address from the TXT record of the DNS entry associated with <url>. If this lookup fails, or the TXT record does not contain an ETN address in the correct format, returns an empty string. <dnssec_valid> will be set true or false according to whether or not the DNS query passes DNSSEC validation.

Parameters
urlthe url to look up
dnssec_validreturn-by-reference for DNSSEC status of query
Returns
a electroneum address (as a string) or an empty string

Definition at line 452 of file dns_utils.cpp.

453 {
454  std::vector<std::string> addresses;
455  // get txt records
456  bool dnssec_available, dnssec_isvalid;
457  std::string oa_addr = DNSResolver::instance().get_dns_format_from_oa_address(url);
458  auto records = DNSResolver::instance().get_txt_record(oa_addr, dnssec_available, dnssec_isvalid);
459 
460  // TODO: update this to allow for conveying that dnssec was not available
461  if (dnssec_available && dnssec_isvalid)
462  {
463  dnssec_valid = true;
464  }
465  else dnssec_valid = false;
466 
467  // for each txt record, try to find a electroneum address in it.
468  for (auto& rec : records)
469  {
471  if (addr.size())
472  {
473  addresses.push_back(addr);
474  }
475  }
476  return addresses;
477 }
::std::string string
Definition: gtest-port.h:1097
std::string address_from_txt_record(const std::string &s)
Definition: dns_utils.cpp:411
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_account_address_as_str_from_url()

std::string tools::dns_utils::get_account_address_as_str_from_url ( const std::string &  url,
bool dnssec_valid,
std::function< std::string(const std::string &, const std::vector< std::string > &, bool)>  dns_confirm 
)

Definition at line 479 of file dns_utils.cpp.

480 {
481  // attempt to get address from dns query
482  auto addresses = addresses_from_url(url, dnssec_valid);
483  if (addresses.empty())
484  {
485  LOG_ERROR("wrong address: " << url);
486  return {};
487  }
488  return dns_confirm(url, addresses, dnssec_valid);
489 }
std::vector< std::string > addresses_from_url(const std::string &url, bool &dnssec_valid)
gets a electroneum address from the TXT record of a DNS entry
Definition: dns_utils.cpp:452
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_txt_records_from_dns()

bool tools::dns_utils::load_txt_records_from_dns ( std::vector< std::string > &  good_records,
const std::vector< std::string > &  dns_urls,
std::string  type 
)

Definition at line 515 of file dns_utils.cpp.

516 {
517  // Prevent infinite recursion when distributing
518  if (dns_urls.empty()) return false;
519 
520  std::vector<std::vector<std::string> > records;
521  records.resize(dns_urls.size());
522 
523  size_t first_index = crypto::rand_idx(dns_urls.size());
524 
525  // send all requests in parallel
526  std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false);
529  for (size_t n = 0; n < dns_urls.size(); ++n)
530  {
531  tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){
532  records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]);
533  });
534  }
535  waiter.wait(&tpool);
536 
537  size_t cur_index = first_index;
538  do
539  {
540  const std::string &url = dns_urls[cur_index];
541  if (!avail[cur_index])
542  {
543  records[cur_index].clear();
544  LOG_PRINT_L2("DNSSEC not available for " << type << " at URL: " << url << ", skipping.");
545  }
546  if (!valid[cur_index])
547  {
548  records[cur_index].clear();
549  LOG_PRINT_L2("DNSSEC validation failed for " << type << " at URL: " << url << ", skipping.");
550  }
551 
552  cur_index++;
553  if (cur_index == dns_urls.size())
554  {
555  cur_index = 0;
556  }
557  } while (cur_index != first_index);
558 
559  size_t num_valid_records = 0;
560 
561  for( const auto& record_set : records)
562  {
563  if (record_set.size() != 0)
564  {
565  num_valid_records++;
566  }
567  }
568 
569  if (num_valid_records < 2)
570  {
571  LOG_PRINT_L1("WARNING: no two valid ElectroneumPulse DNS " << type << " records were received, only " << num_valid_records);
572  return false;
573  }
574 
575  int good_records_index = -1;
576  for (size_t i = 0; i < records.size() - 1; ++i)
577  {
578  if (records[i].size() == 0) continue;
579 
580  for (size_t j = i + 1; j < records.size(); ++j)
581  {
582  if (dns_records_match(records[i], records[j]))
583  {
584  good_records_index = i;
585  break;
586  }
587  }
588  if (good_records_index >= 0) break;
589  }
590 
591  if (good_records_index < 0)
592  {
593  LOG_PRINT_L1("WARNING: no two ElectroneumPulse DNS " << type << " records matched");
594  return false;
595  }
596 
597  good_records = records[good_records_index];
598  return true;
599 }
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
::std::string string
Definition: gtest-port.h:1097
A global thread pool.
Definition: threadpool.h:43
static threadpool & getInstance()
Definition: threadpool.h:46
std::enable_if< std::is_unsigned< T >::value, T >::type rand_idx(T sz)
Definition: crypto.h:244
void wait(threadpool *tpool)
Definition: threadpool.cpp:115
static DNSResolver & instance()
Gets the singleton instance of DNSResolver.
Definition: dns_utils.cpp:383
std::vector< std::string > get_txt_record(const std::string &url, bool &dnssec_available, bool &dnssec_valid)
gets all TXT records from a DNS query for the supplied URL; if no TXT record present returns an empty...
Definition: dns_utils.cpp:365
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_dns_public()

std::vector< std::string > tools::dns_utils::parse_dns_public ( const char *  s)

Definition at line 601 of file dns_utils.cpp.

602 {
603  unsigned ip0, ip1, ip2, ip3;
604  char c;
605  std::vector<std::string> dns_public_addr;
606  if (!strcmp(s, "tcp"))
607  {
608  for (size_t i = 0; i < sizeof(DEFAULT_DNS_PUBLIC_ADDR) / sizeof(DEFAULT_DNS_PUBLIC_ADDR[0]); ++i)
609  dns_public_addr.push_back(DEFAULT_DNS_PUBLIC_ADDR[i]);
610  LOG_PRINT_L0("Using default public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)");
611  }
612  else if (sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4)
613  {
614  if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255)
615  {
616  MERROR("Invalid IP: " << s << ", using default");
617  }
618  else
619  {
620  dns_public_addr.push_back(std::string(s + strlen("tcp://")));
621  }
622  }
623  else
624  {
625  MERROR("Invalid DNS_PUBLIC contents, ignored");
626  }
627  return dns_public_addr;
628 }
#define MERROR(x)
Definition: misc_log_ex.h:73
::std::string string
Definition: gtest-port.h:1097
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
Here is the caller graph for this function: