Browse Source

[trac495] added NXRRSET to classifier result list, and debug msgs

currently, the NSAS appears to work, but it does fail on glue-only referrals
Jelte Jansen 14 years ago
parent
commit
120a7ea6ef

+ 43 - 15
src/lib/asiolink/recursive_query.cc

@@ -84,6 +84,7 @@ public:
     ResolverNSASCallback(RunningQuery* rq) : rq_(rq) {}
     
     void success(const isc::nsas::NameserverAddress& address) {
+        dlog("Found a nameserver, sending query to " + address.getAddress().toText());
         rq_->sendTo(address);
     }
     
@@ -183,7 +184,9 @@ private:
         if (cache_.lookup(question_.getName(), question_.getType(),
                           question_.getClass(), cached_message)) {
             dlog("Message found in cache, returning that");
-            handleRecursiveAnswer(cached_message);
+            if (handleRecursiveAnswer(cached_message)) {
+                stop(true);
+            }
         } else {
             cur_zone_ = ".";
             send();
@@ -196,11 +199,11 @@ private:
         // the RTT
         current_ns_address = address;
         gettimeofday(&current_ns_qsent_time, NULL);
+        ++queries_out_;
         IOFetch query(IPPROTO_UDP, io_, question_,
             current_ns_address.getAddress(),
             53, buffer_, this,
             query_timeout_);
-        ++queries_out_;
         io_.get_io_service().post(query);
     }
     
@@ -212,15 +215,16 @@ private:
             int serverIndex = rand() % uc;
             dlog("Sending upstream query (" + question_.toText() +
                 ") to " + upstream_->at(serverIndex).first);
+            ++queries_out_;
             IOFetch query(IPPROTO_UDP, io_, question_,
                 upstream_->at(serverIndex).first,
                 upstream_->at(serverIndex).second, buffer_, this,
                 query_timeout_);
-            ++queries_out_;
             io_.get_io_service().post(query);
         } else {
             // Ask the NSAS for an address for the current zone,
             // the callback will call the actual sendTo()
+            dlog("Look up nameserver for " + cur_zone_ + " in NSAS");
             nsas_.lookup(cur_zone_, question_.getClass(), nsas_callback_);
         }
     }
@@ -234,21 +238,21 @@ private:
             int serverIndex = rand() % uc;
             dlog("Sending upstream query (" + question_.toText() +
                 ") to " + upstream_->at(serverIndex).first);
+            ++queries_out_;
             IOFetch query(IPPROTO_UDP, io_, question_,
                 upstream_->at(serverIndex).first,
                 upstream_->at(serverIndex).second, buffer_, this,
                 query_timeout_);
-            ++queries_out_;
             io_.get_io_service().post(query);
         } else if (zs > 0) {
             int serverIndex = rand() % zs;
             dlog("Sending query to zone server (" + question_.toText() +
                 ") to " + zone_servers_.at(serverIndex).first);
+            ++queries_out_;
             IOFetch query(IPPROTO_UDP, io_, question_,
                 zone_servers_.at(serverIndex).first,
                 zone_servers_.at(serverIndex).second, buffer_, this,
                 query_timeout_);
-            ++queries_out_;
             io_.get_io_service().post(query);
         } else {
             dlog("Error, no upstream servers to send to.");
@@ -279,19 +283,22 @@ private:
         bool found_ns_address = false;
             
         // If the packet is OK, store it in the cache
-        if (!isc::resolve::ResponseClassifier::error(category)) {
-            cache_.update(incoming);
-        }
+        //if (!isc::resolve::ResponseClassifier::error(category)) {
+        //    cache_.update(incoming);
+        //}
 
         switch (category) {
         case isc::resolve::ResponseClassifier::ANSWER:
         case isc::resolve::ResponseClassifier::ANSWERCNAME:
             // Done. copy and return.
+            dlog("Response is an answer");
+            cache_.update(incoming);
             isc::resolve::copyResponseMessage(incoming, answer_message_);
             return true;
             break;
         case isc::resolve::ResponseClassifier::CNAME:
             dlog("Response is CNAME!");
+            cache_.update(incoming);
             // (unfinished) CNAME. We set our question_ to the CNAME
             // target, then start over at the beginning (for now, that
             // is, we reset our 'current servers' to the root servers).
@@ -315,11 +322,18 @@ private:
             return false;
             break;
         case isc::resolve::ResponseClassifier::NXDOMAIN:
+        case isc::resolve::ResponseClassifier::NXRRSET:
+            dlog("Response is NXDOMAIN or NXRRSET");
             // NXDOMAIN, just copy and return.
+            // no negcache yet
+            //cache_.update(incoming);
+            dlog(incoming.toText());
             isc::resolve::copyResponseMessage(incoming, answer_message_);
             return true;
             break;
         case isc::resolve::ResponseClassifier::REFERRAL:
+            dlog("Response is referral");
+            cache_.update(incoming);
             // Referral. For now we just take the first glue address
             // we find and continue with that
             zone_servers_.clear();
@@ -329,10 +343,11 @@ private:
             // TODO: should we check if it really is subzone?
             for (RRsetIterator rrsi = incoming.beginSection(Message::SECTION_AUTHORITY);
                  rrsi != incoming.endSection(Message::SECTION_AUTHORITY) && !found_ns_address;
-                 rrsi++) {
+                 ++rrsi) {
                 ConstRRsetPtr rrs = *rrsi;
                 if (rrs->getType() == RRType::NS()) {
                     cur_zone_ = rrs->getName().toText();
+                    dlog("Referred to zone " + cur_zone_);
                     found_ns_address = true;
                     break;
                 }
@@ -347,6 +362,7 @@ private:
                 send();
                 return false;
             } else {
+                dlog("No NS RRset in referral?");
                 // TODO this will result in answering with the delegation. oh well
                 isc::resolve::copyResponseMessage(incoming, answer_message_);
                 return true;
@@ -364,6 +380,7 @@ private:
         case isc::resolve::ResponseClassifier::OPCODE:
         case isc::resolve::ResponseClassifier::RCODE:
         case isc::resolve::ResponseClassifier::TRUNCATED:
+            dlog("Error in response, returning SERVFAIL");
             // Should we try a different server rather than SERVFAIL?
             isc::resolve::makeErrorMessage(answer_message_,
                                            Rcode::SERVFAIL());
@@ -501,6 +518,7 @@ public:
         if (queries_out_ > 0) {
             return;
         }
+        dlog("Recursive query stopped, deleting");
         delete this;
     }
 
@@ -545,12 +563,17 @@ public:
             }
         } else if (!done_ && retries_--) {
             // We timed out, but we have some retries, so send again
-            dlog("Timeout, resending query");
-            //current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
+            dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", resending query");
+            if (upstream_->empty()) {
+                current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
+            }
             send();
         } else {
             // out of retries, give up for now
-            //current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
+            dlog("Timeout for " + question_.toText() + " to " + current_ns_address.getAddress().toText() + ", giving up");
+            if (upstream_->empty()) {
+                current_ns_address.updateRTT(isc::nsas::AddressEntry::UNREACHABLE);
+            }
             stop(false);
         }
     }
@@ -569,14 +592,16 @@ RecursiveQuery::resolve(const QuestionPtr& question,
 
     OutputBufferPtr buffer(new OutputBuffer(0));
 
+    dlog("Asked to resolve: " + question->toText());
+    
     dlog("Try out cache first (direct call to resolve)");
     // First try to see if we have something cached in the messagecache
     if (cache_.lookup(question->getName(), question->getType(),
-                      question->getClass(), *answer_message)) {
+                      question->getClass(), *answer_message) &&
+        answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
         dlog("Message found in cache, returning that");
         // TODO: err, should cache set rcode as well?
         answer_message->setRcode(Rcode::NOERROR());
-        std::cout << answer_message->toText();
         callback->success(answer_message);
     } else {
         // Perhaps we only have the one RRset?
@@ -620,10 +645,13 @@ RecursiveQuery::resolve(const Question& question,
     answer_message->setOpcode(isc::dns::Opcode::QUERY());
     answer_message->addQuestion(question);
     
+    dlog("Asked to resolve: " + question.toText());
+    
     // First try to see if we have something cached in the messagecache
     dlog("Try out cache first (started by incoming event)");
     if (cache_.lookup(question.getName(), question.getType(),
-                      question.getClass(), *answer_message)) {
+                      question.getClass(), *answer_message) &&
+        answer_message->getRRCount(Message::SECTION_ANSWER) > 0) {
         dlog("Message found in cache, returning that");
         // TODO: err, should cache set rcode as well?
         answer_message->setRcode(Rcode::NOERROR());

+ 7 - 3
src/lib/resolve/response_classifier.cc

@@ -114,13 +114,17 @@ ResponseClassifier::Category ResponseClassifier::classify(
             );
 
     // If there is nothing in the answer section, it is a referral - unless
-    // there is nothing in the authority section
+    // there is no NS in the authority section
     if (answer.empty()) {
         if (authority.empty()) {
             return (EMPTY);
-        } else {
-            return (REFERRAL);
         }
+        for (int i = 0; i < authority.size(); ++i) {
+            if (authority[i]->getType() == RRType::NS()) {
+                return (REFERRAL);
+            }
+        }
+        return (NXRRSET);
     }
 
     // Look at two cases - one RRset in the answer and multiple RRsets in

+ 1 - 0
src/lib/resolve/response_classifier.h

@@ -53,6 +53,7 @@ public:
         ANSWERCNAME,        ///< Response was a CNAME chain ending in an answer
         CNAME,              ///< Response was a CNAME
         NXDOMAIN,           ///< Response was an NXDOMAIN
+        NXRRSET,            ///< Response was name exists, but type does not
         REFERRAL,           ///< Response contains a referral
 
         // Codes indicating that a message is invalid.  Note that the error()

+ 17 - 0
src/lib/resolve/tests/response_classifier_unittest.cc

@@ -80,6 +80,8 @@ public:
             RRType::CNAME(), RRTTL(300))),
         rrs_in_ns_(new RRset(Name("example.com"), RRClass::IN(),
             RRType::NS(), RRTTL(300))),
+        rrs_in_soa_(new RRset(Name("example.com"), RRClass::IN(),
+            RRType::SOA(), RRTTL(300))),
         rrs_in_txt_www(new RRset(Name("www.example.com"), RRClass::IN(),
             RRType::TXT(), RRTTL(300))),
         cname_target("."),
@@ -115,6 +117,9 @@ public:
         // Set up an imaginary NS RRset for an authority section
         rrs_in_ns_->addRdata(ConstRdataPtr(new NS(Name("ns0.isc.org"))));
         rrs_in_ns_->addRdata(ConstRdataPtr(new NS(Name("ns0.example.org"))));
+        
+        // And an imaginary SOA
+        rrs_in_soa_->addRdata(ConstRdataPtr(new SOA(Name("ns0.example.org"), Name("root.example.org"), 1, 2, 3, 4, 5)));
 
         // Set up the records for the www host
         rrs_in_a_www->addRdata(ConstRdataPtr(new A("1.2.3.4")));
@@ -146,6 +151,7 @@ public:
     RRsetPtr    rrs_in_cname_www1;  // www1.example.com IN CNAME
     RRsetPtr    rrs_in_cname_www2;  // www2.example.com IN CNAME
     RRsetPtr    rrs_in_ns_;         // example.com IN NS
+    RRsetPtr    rrs_in_soa_;        // example.com IN SOA
     RRsetPtr    rrs_in_txt_www;     // www.example.com IN TXT
     Name        cname_target;       // Used in response classifier to
                                     // store the target of a possible
@@ -349,6 +355,17 @@ TEST_F(ResponseClassifierTest, EmptyAnswerReferral) {
 
 }
 
+// Test if we get a NOERROR answer that contains neither an actual
+// answer nor a delegation
+TEST_F(ResponseClassifierTest, NoErrorNoData) {
+
+    msg_a.addRRset(Message::SECTION_AUTHORITY, rrs_in_soa_);
+    EXPECT_EQ(ResponseClassifier::NXRRSET,
+        ResponseClassifier::classify(qu_in_a_www, msg_a, cname_target,
+                                     cname_count));
+
+}
+
 // Check the case where we have a simple answer in the answer section.  This
 // occurs when the QNAME/QTYPE/QCLASS matches one of the RRsets in the
 // answer section - expect when the QTYPE is ANY, in which case the match