int MaxRetrievalRecursions = 10;
}
+Cname::Cname()
+ : Host()
+ , Ttl()
+{}
+
+Cname::Cname(const std::string &host, const uint32_t ttl)
+ : Host( host )
+ , Ttl( ttl )
+{}
+
DnsCache::DnsCache(const IoServiceItem &io_serv,
const std::string &cache_file)
: IpCache()
const Cname &cname)
{
GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
- << " to " << cname.first;
+ << " to " << cname.Host;
CnameCache[hostname] = cname;
HasChanged = true;
}
}
+/**
+ * @returns empty list if no (up to date) ips for hostname in cache
+ */
HostAddressVec DnsCache::get_ips(const std::string &hostname,
const bool check_up_to_date)
{
if (check_up_to_date)
{
HostAddressVec result_up_to_date;
- int threshold = DnsMaster::get_instance()
- ->get_resolved_ip_ttl_threshold();
+ uint32_t threshold = static_cast<uint32_t>(
+ DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() );
BOOST_FOREACH( const HostAddress &addr, result )
{
if (addr.get_ttl().get_updated_value() > threshold)
return result;
}
-std::string DnsCache::get_cname(const std::string &hostname,
- const bool check_up_to_date)
+/**
+ * @returns empty cname if no (up to date cname) for hostname in cache
+ */
+Cname DnsCache::get_cname(const std::string &hostname,
+ const bool check_up_to_date)
{
Cname result_obj = CnameCache[hostname];
GlobalLogger.info() << "DnsCache: request CNAME for " << hostname
- << " --> \"" << result_obj.first << "\"";
- if (check_up_to_date)
+ << " --> \"" << result_obj.Host << "\"";
+ if (result_obj.Host.empty())
+ return result_obj;
+
+ else if (check_up_to_date)
{
- if (result_obj.second.get_updated_value() > DnsMaster::get_instance()
+ if (result_obj.Ttl.get_updated_value() > DnsMaster::get_instance()
->get_resolved_ip_ttl_threshold())
- return result_obj.first;
+ return result_obj;
else
{
- GlobalLogger.debug() << "DnsCache: Cname is out of date";
- return "";
+ GlobalLogger.debug() << "DnsCache: CNAME is out of date";
+ return Cname(); // same as if there was no cname for hostname
}
}
else
- return result_obj.first;
+ return result_obj;
}
// underlying assumption in this function: for a hostname, the cache has either
const bool check_up_to_date)
{
std::string current_host = hostname;
+ Cname current_cname;
HostAddressVec result = get_ips(current_host);
int n_recursions = 0;
+ uint32_t min_cname_ttl = 0xffff; // largest possible unsigned 4-byte value
while ( result.empty() )
{
- current_host = get_cname(current_host, check_up_to_date);
+ current_cname = get_cname(current_host, check_up_to_date);
+ current_host = current_cname.Host;
if (current_host.empty())
break;
else if (++n_recursions >= Config::MaxRetrievalRecursions)
break;
}
else
+ {
+ min_cname_ttl = min(min_cname_ttl, current_cname.Ttl.get_value());
result = get_ips(current_host, check_up_to_date);
+ }
+ }
+
+ GlobalLogger.debug() << "DnsCache: recursive IP retrieval resulted in "
+ << result.size() << "-list after " << n_recursions
+ << " recursions";
+
+ // adjust ttl to min of ttl and min_cname_ttl
+ if (n_recursions > 0)
+ {
+ TimeToLive cname_ttl(min_cname_ttl);
+
+ BOOST_FOREACH( HostAddress &addr, result )
+ {
+ if (addr.get_ttl().get_value() > min_cname_ttl)
+ addr.set_ttl(cname_ttl);
+ }
}
+
return result;
}
+/**
+ * from a list of CNAMEs find the first one that is out of date
+ *
+ * required in ResolverBase::get_skipper
+ *
+ * Assume you have the following situation in cache with TTLs below:
+ * hostname --> cname1 --> cname2 --> ... --> cnameN [--> IP]
+ * 100 0 --> return cname2
+ * 100 100 100 100 --> return cnameN
+ * ( with N < Config::MaxRetrievalRecursions )
+ * hostname --> IP (no cnames involved) --> return hostname
+ */
+std::string DnsCache::get_first_outdated_cname(const std::string &hostname,
+ const uint32_t ttl_thresh)
+{
+ std::string up_to_date_host = hostname;
+ Cname cname;
+ int n_recursions = 0;
+ while (true)
+ {
+ if (++n_recursions >= Config::MaxRetrievalRecursions)
+ {
+ GlobalLogger.warning() << "DnsCache: reached recursion limit of "
+ << n_recursions << " in search of outdated CNAMEs!";
+ break;
+ }
+
+ cname = get_cname(up_to_date_host);
+ if (cname.Host.empty())
+ // reached end of cname list
+ break;
+ else if (cname.Ttl.get_updated_value() > ttl_thresh)
+ // cname is up to date --> continue looking
+ up_to_date_host = cname.Host;
+ else
+ // cname is out of date --> return that
+ break;
+ }
+ return up_to_date_host;
+}
+
// (created using vim -- the world's best text editor)