, LogPrefix( "DnsResolver" )
, RandomIdGenerator()
, RequestId( 0 )
- , Recursor()
, OperationCancelled( false )
{
std::stringstream temp;
// create DNS request
boost::net::dns::message dns_message( ResolverBase::Hostname, Protocol );
- dns_message.recursive(false);
+ dns_message.recursive(true);
dns_message.action(boost::net::dns::message::query);
dns_message.opcode(boost::net::dns::message::squery);
// remember cname list (if there were any)
BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
{
- GlobalLogger.debug() << LogPrefix << "Remember CNAME "
- << host_and_cname.first << " --> " << host_and_cname.second.first;
+ GlobalLogger.info() << LogPrefix << "Remember CNAME "
+ << host_and_cname.first << " --> " << host_and_cname.second.Host;
ResolverBase::update_cache(host_and_cname.first, host_and_cname.second);
}
// re-start resolving with that
handle_cname(result_cnames);
else
- { // no answers --> check for name_servers in authorities section
- if ( !result_name_servers.empty() )
- GlobalLogger.warning() << LogPrefix
- << "Received NS records in answers! "
- << "That is quite unexpected...";
- GlobalLogger.debug() << "Checking AUTHORITIES section of dns reply";
- gather_results(result_message.authorites(), &result_ips,
- &result_cnames, &result_name_servers);
- GlobalLogger.debug() << "Checking ADDITIONALS section of dns reply";
- gather_results(result_message.additionals(), &result_ips,
- &result_cnames, &result_name_servers);
-
- // search for a name_server for which an IP is given
- bool have_recursed = false;
- BOOST_FOREACH( const string_pair &name_server, result_name_servers )
- {
- if (name_server.second == Hostname)
- { // in case we try to resolve IP for name server, do not use same
- GlobalLogger.debug() << LogPrefix
- << "Name server found is same as hostname --> skip";
- continue;
- }
-
- // go through ips and look for match
- BOOST_FOREACH( const host_addr_pair &host_and_addr, result_ips )
- {
- if (name_server.second == host_and_addr.first)
- {
- GlobalLogger.info() << LogPrefix << "Ask next name_server "
- << name_server.second << " with IP "
- << host_and_addr.second.get_ip() << " (responsible for "
- << name_server.first << ")";
- have_recursed = true;
- handle_recurse( host_and_addr.second );
- break;
- }
- }
- if (have_recursed)
- break;
- }
-
- if ( !have_recursed )
- { // no name_server with ip found -- strange
- if (result_name_servers.empty())
- {
- GlobalLogger.error() << LogPrefix << "Result contained neither "
- << "IP nor CNAME nor name server --> cannot proceed!";
- handle_unavailable();
- }
- else
- {
- GlobalLogger.warning() << LogPrefix
- << "There are " << result_name_servers.size()
- << " name_servers given but none with IP!";
- handle_recurse_without_ip(result_name_servers[0].second);
- }
- }
+ { // no answers --> cannot proceed
+ GlobalLogger.warning() << LogPrefix << "No IP nor CNAME received! "
+ << "--> schedule retry";
+ schedule_retry();
}
}
-void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers,
+/**
+ * gather IPs, CNAMEs and name servers from list of resource records;
+ *
+ * can be run on anwers(), autorities() and additional() sections of dns reply
+ * messages
+ *
+ * @param rr_list: input list of resource records
+ * @param result_ips: output vector of ips
+ * @param result_cnames: output vector of cnames
+ * @param result_name_servers: output vector of name servers
+ */
+void DnsResolver::gather_results(const boost::net::dns::rr_list_t *rr_list,
std::vector<host_addr_pair> *result_ips,
std::vector<src_cname_pair> *result_cnames,
std::vector<string_pair> *result_name_servers)
{
using boost::net::dns::resource_base_t;
boost::posix_time::ptime now =boost::posix_time::second_clock::local_time();
- BOOST_FOREACH( boost::shared_ptr<resource_base_t> rr_item, *answers )
+ BOOST_FOREACH( boost::shared_ptr<resource_base_t> rr_item, *rr_list )
{
boost::net::dns::type_t rr_type = rr_item->rtype();
uint32_t ttl = rr_item->ttl();
// We assume here that this list might not be in order but that all cnames
// form a single list (form one connected list and not several isolated)
- // host_and_cname.second is a Cname, which is a pair (destination, ttl)
std::string last_cname = "";
bool could_be_last;
BOOST_REVERSE_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
could_be_last = true;
BOOST_REVERSE_FOREACH( const src_cname_pair &other, result_cnames )
{
- if (other.first == host_and_cname.second.first)
+ if (other.first == host_and_cname.second.Host)
{ // found cname for current cname
could_be_last = false;
break;
}
if (could_be_last)
{
- last_cname = host_and_cname.second.first;
+ last_cname = host_and_cname.second.Host;
break;
}
}
GlobalLogger.info() << LogPrefix << "Result CNAMEs were:";
BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames )
GlobalLogger.info() << LogPrefix << host_and_cname.first << " --> "
- << host_and_cname.second.first;
+ << host_and_cname.second.Host;
handle_unavailable();
}
else
if ( !cached_data.empty() )
{
bool was_success = true;
- int recursion_count = 1; // define cache access as only 1
- finalize_resolve(was_success, recursion_count);
+ int cname_count = 1; // define cache access as only 1
+ finalize_resolve(was_success, cname_count);
}
else
{ // get resolver for canonical name
- // as opposed to the interal Recursor variable used in
- // handle_recurse, this is a "proper" resolver that is maintained
- // and cached by DnsMaster --> independent of this Resolver
ResolverItem resolver = DnsMaster::get_instance()
->get_resolver_for(last_cname, Protocol);
callback_type callback = boost::bind(
void DnsResolver::cname_resolve_callback(const bool was_success,
- const int recursion_count)
+ const int cname_count)
{
if ( OperationCancelled )
{ // async_resolve was cancelled --> callbacks already called
else
GlobalLogger.info() << LogPrefix << "CNAME resolution failed";
// no use to schedule retry in this case since cname resolver must have
- // failed several times and we can just re-start the same procedure with
- // the same information (in recursion can try different name server)
- // --> no schedule_retry
+ // failed several times and we can only re-start the same procedure with
+ // the same information
// cname counts like one more recursion step ...
- finalize_resolve(was_success, recursion_count+1);
-}
-
-
-void DnsResolver::handle_recurse(const HostAddress &name_server)
-{
- // get resolver for same hostname but using a different name server
- if (Recursor)
- {
- if (Recursor->is_resolving())
- {
- GlobalLogger.warning() << LogPrefix << "Recursor is resolving! "
- << "Will cancel and reset";
- Recursor->cancel_resolve();
- }
- else
- GlobalLogger.warning() << LogPrefix
- << "Recursor has not been reset!";
- Recursor.reset();
- }
-
- Recursor = DnsMaster::get_instance()->get_recursor_for(
- Hostname, Protocol, name_server.get_ip());
- callback_type callback = boost::bind(
- &DnsResolver::recursive_resolve_callback,
- this, name_server.get_ttl().get_value(),
- _1, _2 );
- Recursor->async_resolve( callback );
-
- // do not cancel timers or reset RetryCount
- //stop_trying();
-}
-
-
-void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl,
- const bool was_success,
- const int recursion_count)
-{
- GlobalLogger.debug()
- << "Recursion back at request with name server " << NameServer;
-
- // do not need recursor any more; next time re-create from different random
- // name server; may have been reset already in cancel_resolve(), so that
- // is ok. If not, issue a warning
- if ( !Recursor )
- {
- if ( !OperationCancelled )
- GlobalLogger.warning() << LogPrefix
- << "Recursor was reset before callback!";
- }
- else
- Recursor.reset();
-
- if ( OperationCancelled )
- { // async_resolve was cancelled --> callbacks already called
- GlobalLogger.info() << LogPrefix
- << "Ignoring recursion results since we were cancelled";
- return;
- }
- else if (was_success)
- {
- // make sure the saved TTL is not larger than the one we found here
- ResolverBase::update_cache(min_ttl);
- finalize_resolve(was_success, recursion_count+1);
- }
- else
- {
- GlobalLogger.info() << LogPrefix << "Recursive resolution failed";
- schedule_retry();
- }
-}
-
-
-void DnsResolver::handle_recurse_without_ip(const std::string &name_server)
-{
- // get resolver for name_server
- // save in Recursor although it is a "proper" resolver (so result is cached)
- if (Recursor)
- {
- if (Recursor->is_resolving())
- {
- GlobalLogger.warning() << LogPrefix << "Recursor is resolving! "
- << "Will cancel and reset";
- Recursor->cancel_resolve();
- }
- else
- GlobalLogger.warning() << LogPrefix
- << "Recursor has not been reset!";
- Recursor.reset();
- }
- Recursor = DnsMaster::get_instance()->get_resolver_for(name_server,
- Protocol);
-
- // check for IPs in cache
- if (Recursor->get_resolved_ip_count() == 0)
- {
- GlobalLogger.info() << LogPrefix
- << "Start to resolve address of name server " << name_server;
- callback_type callback = boost::bind(
- &DnsResolver::name_server_resolve_callback,
- this, _1, _2);
- Recursor->async_resolve( callback );
- }
- else
- {
- GlobalLogger.info() << LogPrefix << "Use cached ip for name server "
- << name_server;
- HostAddress ip = Recursor->get_next_ip();
- Recursor.reset();
- handle_recurse(ip);
- }
-}
-
-void DnsResolver::name_server_resolve_callback(const bool was_success,
- const int recursion_count)
-{
- if (OperationCancelled)
- {
- GlobalLogger.info() << LogPrefix
- << "Ignoring name server IP results since we were cancelled";
- return;
- }
- else if (was_success)
- {
- HostAddress ip = Recursor->get_next_ip();
- GlobalLogger.info() << LogPrefix << "Found IP " << ip.get_ip()
- << " for name server " << Recursor->get_hostname();
- Recursor.reset();
- handle_recurse(ip);
- }
- else
- {
- GlobalLogger.info() << LogPrefix << "Failed to find IP for name server"
- << Recursor->get_hostname() << " --> schedule retry";
- Recursor.reset();
- schedule_retry();
- }
+ finalize_resolve(was_success, cname_count+1);
}
void DnsResolver::finalize_resolve(const bool was_success,
- const int recursion_count)
+ const int cname_count)
{
// some consistency checks; failure might indicate a situation I had not
// anticipated during programming but might not be harmfull yet
stop_trying();
// schedule callbacks, clearing callback list
- ResolverBase::schedule_callbacks(was_success, recursion_count);
+ ResolverBase::schedule_callbacks(was_success, cname_count);
// finalize
GlobalLogger.notice() << LogPrefix << "finalized resolve"
<< " with success = " << was_success
- << " and recursion_count = " << recursion_count;
+ << " and cname_count = " << cname_count;
IsResolving = false;
}
return;
}
- if ( Recursor )
- Recursor->cancel_resolve(); // does not hurt even if it is not resolving
-
// set before finalize_resolve so can check in finalize_resolve that ID is
// always 0; ID is not used any more since handle_dns_result stops if
// OperationCancelled is true
RequestId = 0;
bool was_success = false;
- int recursion_count = 1;
- finalize_resolve(was_success, recursion_count);
+ int cname_count = 1;
+ finalize_resolve(was_success, cname_count);
// set after finalize_resolve, so can check in finalize_resolve that
// OperationCancelled is never true
void DnsResolver::schedule_retry()
{
- // this function is called in all sorts of error cases
- // --> need to clean up a bit
- if ( Recursor )
- {
- Recursor->cancel_resolve();
- Recursor.reset();
- }
+ // cancel timers
ResolveTimeoutTimer.cancel();
PauseBeforeRetryTimer.cancel();