simplified dns (no self-made recursion); merge PingScheduler and PingRotate; make...
[pingcheck] / src / dns / dnsresolver.cpp
index 139219c..1e236d3 100644 (file)
@@ -72,7 +72,6 @@ DnsResolver::DnsResolver(IoServiceItem &io_serv,
     , LogPrefix( "DnsResolver" )
     , RandomIdGenerator()
     , RequestId( 0 )
-    , Recursor()
     , OperationCancelled( false )
 {
     std::stringstream temp;
@@ -129,7 +128,7 @@ void DnsResolver::do_resolve()
 
     // 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);
 
@@ -236,8 +235,8 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error,
     // 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);
     }
 
@@ -248,67 +247,25 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error,
         // 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)
@@ -316,7 +273,7 @@ void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers,
 {
     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();
@@ -453,7 +410,6 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
     // 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 )
@@ -461,7 +417,7 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &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;
@@ -469,7 +425,7 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
         }
         if (could_be_last)
         {
-            last_cname = host_and_cname.second.first;
+            last_cname = host_and_cname.second.Host;
             break;
         }
     }
@@ -482,7 +438,7 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
         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
@@ -493,14 +449,11 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
         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(
@@ -518,7 +471,7 @@ void DnsResolver::handle_cname(const std::vector<src_cname_pair> &result_cnames)
 
 
 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
@@ -531,153 +484,16 @@ void DnsResolver::cname_resolve_callback(const bool was_success,
     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
@@ -698,12 +514,12 @@ void DnsResolver::finalize_resolve(const bool was_success,
     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;
 }
 
@@ -749,17 +565,14 @@ void DnsResolver::cancel_resolve()
         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
@@ -799,13 +612,7 @@ void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error)
 
 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();