38 #include <boost/optional.hpp> 40 #include <boost/filesystem/fstream.hpp> 41 #include <boost/thread/mutex.hpp> 42 #include <boost/thread/thread.hpp> 43 #include <boost/algorithm/string/join.hpp> 46 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 47 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "net.dns" 49 static const char *DEFAULT_DNS_PUBLIC_ADDR[] =
58 static boost::mutex instance_lock;
103 static const char*
const*
106 static const char *
const ds[] =
108 ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n",
109 ". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n",
124 static const char *get_record_name(
int record_type)
128 case DNS_TYPE_A:
return "A";
129 case DNS_TYPE_TXT:
return "TXT";
130 case DNS_TYPE_AAAA:
return "AAAA";
131 default:
return "unknown";
144 std::stringstream ss;
145 unsigned int bytes[4];
146 for (
int i = 0; i < 4; i++)
148 unsigned char a = src[i];
151 ss << bytes[0] <<
"." 168 std::stringstream ss;
169 unsigned int bytes[8];
170 for (
int i = 0; i < 8; i++)
172 unsigned char a = src[i];
175 ss << bytes[0] <<
":" 195 template<
typename type,
void (*freefunc)(type*)>
211 operator type *() {
return ptr; }
214 operator const type*()
const {
return &ptr; }
232 operator char*() {
return str; }
238 static void add_anchors(
ub_ctx *ctx)
240 const char *
const *ds = ::get_builtin_ds();
243 MINFO(
"adding trust anchor: " << *ds);
248 DNSResolver::DNSResolver() : m_data(new DNSResolverData())
250 int use_dns_public = 0;
251 std::vector<std::string> dns_public_addr;
252 const char *DNS_PUBLIC = getenv(
"DNS_PUBLIC");
256 if (!dns_public_addr.empty())
258 MGINFO(
"Using public DNS server(s): " << boost::join(dns_public_addr,
", ") <<
" (TCP)");
263 MERROR(
"Failed to parse DNS_PUBLIC");
272 for (
const auto &
ip: dns_public_addr)
283 add_anchors(m_data->m_ub_context);
290 bool available, valid;
291 static const char *probe_hostname =
"updates.electroneumpulse.org";
292 auto records = get_txt_record(probe_hostname, available, valid);
295 MINFO(
"Failed to verify DNSSEC record from " << probe_hostname <<
", falling back to TCP with well known DNSSEC resolvers");
298 add_anchors(m_data->m_ub_context);
299 for (
const auto &
ip: DEFAULT_DNS_PUBLIC_ADDR)
319 std::vector<std::string> DNSResolver::get_record(
const std::string& url,
int record_type, boost::optional<std::string> (*reader)(
const char *,
size_t),
bool& dnssec_available,
bool& dnssec_valid)
321 std::vector<std::string> addresses;
322 dnssec_available =
false;
323 dnssec_valid =
false;
325 if (!check_address_syntax(url.c_str()))
336 dnssec_available = (result->secure || result->bogus);
337 dnssec_valid = result->secure && !result->bogus;
338 if (result->havedata)
340 for (
size_t i=0; result->data[i] != NULL; i++)
342 boost::optional<std::string>
res = (*reader)(result->data[i], result->len[i]);
345 MINFO(
"Found \"" << *
res <<
"\" in " << get_record_name(record_type) <<
" record for " << url);
346 addresses.push_back(*
res);
357 return get_record(url, DNS_TYPE_A,
ipv4_to_string, dnssec_available, dnssec_valid);
362 return get_record(url, DNS_TYPE_AAAA,
ipv6_to_string, dnssec_available, dnssec_valid);
367 return get_record(url, DNS_TYPE_TXT,
txt_to_string, dnssec_available, dnssec_valid);
373 auto first_at = addr.find(
"@");
374 if (first_at == std::string::npos)
378 addr.replace(first_at, 1,
".");
385 boost::lock_guard<boost::mutex> lock(instance_lock);
388 return staticInstance;
396 bool DNSResolver::check_address_syntax(
const char *addr)
const 399 if (strchr(addr,
'.') == NULL)
414 auto pos = s.find(
"oa1:etn");
415 if (pos == std::string::npos)
418 pos = s.find(
"recipient_address=", pos);
419 if (pos == std::string::npos)
423 auto pos2 = s.find(
";", pos);
424 if (pos2 != std::string::npos)
427 if (pos2 - pos == 98)
429 return s.substr(pos, 98);
431 else if (pos2 - pos == 109)
433 return s.substr(pos, 109);
454 std::vector<std::string> addresses;
456 bool dnssec_available, dnssec_isvalid;
461 if (dnssec_available && dnssec_isvalid)
465 else dnssec_valid =
false;
468 for (
auto& rec : records)
473 addresses.push_back(addr);
483 if (addresses.empty())
488 return dns_confirm(url, addresses, dnssec_valid);
493 bool dns_records_match(
const std::vector<std::string>&
a,
const std::vector<std::string>& b)
495 if (
a.size() != b.size())
return false;
497 for (
const auto& record_in_a :
a)
500 for (
const auto& record_in_b : b)
502 if (record_in_a == record_in_b)
508 if (!ok)
return false;
518 if (dns_urls.empty())
return false;
520 std::vector<std::vector<std::string> > records;
521 records.resize(dns_urls.size());
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)
531 tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){
537 size_t cur_index = first_index;
541 if (!avail[cur_index])
543 records[cur_index].clear();
544 LOG_PRINT_L2(
"DNSSEC not available for " << type <<
" at URL: " << url <<
", skipping.");
546 if (!valid[cur_index])
548 records[cur_index].clear();
549 LOG_PRINT_L2(
"DNSSEC validation failed for " << type <<
" at URL: " << url <<
", skipping.");
553 if (cur_index == dns_urls.size())
557 }
while (cur_index != first_index);
559 size_t num_valid_records = 0;
561 for(
const auto& record_set : records)
563 if (record_set.size() != 0)
569 if (num_valid_records < 2)
571 LOG_PRINT_L1(
"WARNING: no two valid ElectroneumPulse DNS " << type <<
" records were received, only " << num_valid_records);
575 int good_records_index = -1;
576 for (
size_t i = 0; i < records.size() - 1; ++i)
578 if (records[i].size() == 0)
continue;
580 for (
size_t j = i + 1; j < records.size(); ++j)
582 if (dns_records_match(records[i], records[j]))
584 good_records_index = i;
588 if (good_records_index >= 0)
break;
591 if (good_records_index < 0)
593 LOG_PRINT_L1(
"WARNING: no two ElectroneumPulse DNS " << type <<
" records matched");
597 good_records = records[good_records_index];
603 unsigned ip0, ip1, ip2, ip3;
605 std::vector<std::string> dns_public_addr;
606 if (!strcmp(s,
"tcp"))
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)");
612 else if (sscanf(s,
"tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4)
614 if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255)
616 MERROR(
"Invalid IP: " << s <<
", using default");
620 dns_public_addr.push_back(
std::string(s + strlen(
"tcp://")));
625 MERROR(
"Invalid DNS_PUBLIC contents, ignored");
627 return dns_public_addr;
int ub_ctx_resolvconf(struct ub_ctx *ctx, const char *fname)
int ub_ctx_set_option(struct ub_ctx *ctx, const char *opt, const char *val)
std::enable_if< std::is_unsigned< T >::value, T >::type rand_idx(T sz)
Archiver & operator &(Archiver &ar, Student &s)
struct ub_ctx * ub_ctx_create(void)
boost::endian::big_uint32_t ip
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
int ub_ctx_set_fwd(struct ub_ctx *ctx, const char *addr)
int ub_ctx_hosts(struct ub_ctx *ctx, const char *fname)
void ub_ctx_delete(struct ub_ctx *ctx)
int ub_resolve(struct ub_ctx *ctx, const char *name, int rrtype, int rrclass, struct ub_result **result)
void ub_resolve_free(struct ub_result *result)
int ub_ctx_add_ta(struct ub_ctx *ctx, const char *ta)