Browse Source

[trac859] Start delegating as deep as possible

Michal 'vorner' Vaner 14 years ago
parent
commit
b963854734
1 changed files with 53 additions and 1 deletions
  1. 53 1
      src/lib/resolve/recursive_query.cc

+ 53 - 1
src/lib/resolve/recursive_query.cc

@@ -28,6 +28,7 @@
 #include <dns/message.h>
 #include <dns/opcode.h>
 #include <dns/exceptions.h>
+#include <dns/rdataclass.h>
 
 #include <resolve/resolve.h>
 #include <cache/resolver_cache.h>
@@ -48,6 +49,23 @@ using namespace isc::asiolink;
 namespace isc {
 namespace asiodns {
 
+namespace {
+// Function to check if the given name/class has any address in the cache
+bool
+hasAddress(const Name& name, const RRClass& rrClass,
+      const isc::cache::ResolverCache& cache)
+{
+    // FIXME: If we are single-stack and we get only the other type of
+    // address, what should we do? In that case, it will be considered
+    // unreachable, which is most probably true, because A and AAAA will
+    // usually have the same RTT, so we should have both or none from the
+    // glue.
+    return (cache.lookup(name, RRType::A(), rrClass) != RRsetPtr() ||
+            cache.lookup(name, RRType::AAAA(), rrClass) != RRsetPtr());
+}
+
+}
+
 typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
 
 // Here we do not use the typedef above, as the SunStudio compiler
@@ -239,7 +257,6 @@ private:
     // if we have a response for our query stored already. if
     // so, call handlerecursiveresponse(), if not, we call send()
     void doLookup() {
-        cur_zone_ = ".";
         dlog("doLookup: try cache");
         Message cached_message(Message::RENDER);
         isc::resolve::initResponseMessage(question_, cached_message);
@@ -255,6 +272,41 @@ private:
                 stop();
             }
         } else {
+            dlog("doLookup: get lowest usable delegation from cache");
+            cur_zone_ = ".";
+            bool foundAddress(false);
+            RRsetPtr cachedNS;
+            Name tryName(question_.getName());
+            // Look for delegation point from bottom, until we find one with
+            // IP address or get to root.
+            //
+            // We need delegation with IP address so we can ask it right away.
+            // If we don't have the IP address, we would need to ask above it
+            // anyway in the best case, and the NS could be inside the zone,
+            // and we could get all loopy with the NSAS in the worst case.
+            while (!foundAddress && tryName.getLabelCount() > 1 &&
+                   (cachedNS = cache_.lookupDeepestNS(tryName,
+                                                     question_.getClass())) !=
+                   RRsetPtr()) {
+                // Look if we have an IP address for the NS
+                for (RdataIteratorPtr ns(cachedNS->getRdataIterator());
+                     !ns->isLast(); ns->next()) {
+                    // Do we have IP for this specific NS?
+                    if (hasAddress(dynamic_cast<const rdata::generic::NS&>(
+                                  ns->getCurrent()).getNSName(),
+                              question_.getClass(), cache_)) {
+                        // Found one, stop checking and use this zone
+                        // (there may be more addresses, that's only better)
+                        foundAddress = true;
+                        cur_zone_ = cachedNS->getName().toText();
+                        break;
+                    }
+                }
+                // We don't have anything for this one, so try something higher
+                if (!foundAddress && tryName.getLabelCount() > 1) {
+                    tryName = tryName.split(1);
+                }
+            }
             send();
         }