Browse Source

[1386] EDNS fallback on FORMERR

Dima Volodin 13 years ago
parent
commit
e3c35e7514
3 changed files with 49 additions and 15 deletions
  1. 11 7
      src/lib/asiodns/io_fetch.cc
  2. 6 2
      src/lib/asiodns/io_fetch.h
  3. 32 6
      src/lib/resolve/recursive_query.cc

+ 11 - 7
src/lib/asiodns/io_fetch.cc

@@ -175,12 +175,12 @@ struct IOFetchData {
 /// IOFetch Constructor - just initialize the private data
 
 IOFetch::IOFetch(Protocol protocol, IOService& service,
-    const isc::dns::Question& question, const IOAddress& address, uint16_t port,
-    OutputBufferPtr& buff, Callback* cb, int wait)
+    const isc::dns::Question& question, const IOAddress& address,
+    uint16_t port, OutputBufferPtr& buff, Callback* cb, int wait, bool edns)
 {
     MessagePtr query_msg(new Message(Message::RENDER));
     initIOFetch(query_msg, protocol, service, question, address, port, buff,
-                cb, wait);
+                cb, wait, edns);
 }
 
 IOFetch::IOFetch(Protocol protocol, IOService& service,
@@ -214,7 +214,7 @@ void
 IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& service,
                      const isc::dns::Question& question,
                      const IOAddress& address, uint16_t port,
-                     OutputBufferPtr& buff, Callback* cb, int wait)
+                     OutputBufferPtr& buff, Callback* cb, int wait, bool edns)
 {
     data_ = boost::shared_ptr<IOFetchData>(new IOFetchData(
         protocol, service, address, port, buff, cb, wait));
@@ -224,9 +224,13 @@ IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& servic
     query_msg->setRcode(Rcode::NOERROR());
     query_msg->setHeaderFlag(Message::HEADERFLAG_RD);
     query_msg->addQuestion(question);
-    EDNSPtr edns_query(new EDNS());
-    edns_query->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
-    query_msg->setEDNS(edns_query);
+
+    if (edns) {
+        EDNSPtr edns_query(new EDNS());
+        edns_query->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
+        query_msg->setEDNS(edns_query);
+    }
+
     MessageRenderer renderer(*data_->msgbuf);
     query_msg->toWire(renderer);
 }

+ 6 - 2
src/lib/asiodns/io_fetch.h

@@ -131,11 +131,14 @@ public:
     ///        and deleting it if necessary.
     /// \param wait Timeout for the fetch (in ms).  The default value of
     ///        -1 indicates no timeout.
+    /// \param edns true if the request should be EDNS. The default value is
+    ///        true.
     IOFetch(Protocol protocol, isc::asiolink::IOService& service,
         const isc::dns::Question& question,
         const isc::asiolink::IOAddress& address,
         uint16_t port, isc::util::OutputBufferPtr& buff, Callback* cb,
-        int wait = -1);
+        int wait = -1,
+        bool edns = true);
 
     /// \brief Constructor
     ///  This constructor has one parameter "query_message", which
@@ -206,7 +209,8 @@ private:
     void initIOFetch(isc::dns::MessagePtr& query_message, Protocol protocol,
             isc::asiolink::IOService& service, const isc::dns::Question& question,
             const isc::asiolink::IOAddress& address, uint16_t port,
-            isc::util::OutputBufferPtr& buff, Callback* cb, int wait);
+            isc::util::OutputBufferPtr& buff, Callback* cb, int wait,
+	    bool edns = true);
 
     /// \brief Log I/O Failure
     ///

+ 32 - 6
src/lib/resolve/recursive_query.cc

@@ -229,6 +229,9 @@ private:
     // case of a TCP packet being returned with the TC bit set.
     IOFetch::Protocol protocol_;
 
+    // EDNS flag
+    bool edns_;
+
     // To prevent both unreasonably long cname chains and cname loops,
     // we simply keep a counter of the number of CNAMEs we have
     // followed so far (and error if it exceeds RESOLVER_MAX_CNAME_CHAIN
@@ -358,17 +361,19 @@ private:
             IOFetch query(protocol_, io_, question_,
                 current_ns_address.getAddress(),
                 53, buffer_, this,
-                query_timeout_);
+                query_timeout_, edns_);
             io_.get_io_service().post(query);
         }
     }
     
     // 'general' send, ask the NSAS to give us an address.
-    void send(IOFetch::Protocol protocol = IOFetch::UDP) {
+    void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) {
         protocol_ = protocol;   // Store protocol being used for this
+        edns_ = edns;
         if (test_server_.second != 0) {
             // Send query to test server
-            LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
+            LOG_DEBUG(isc::resolve::logger,
+                      RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
                 .arg(questionText(question_)).arg(test_server_.first);
             gettimeofday(&current_ns_qsent_time, NULL);
             ++outstanding_events_;
@@ -381,8 +386,9 @@ private:
         } else {
             // Ask the NSAS for an address for the current zone,
             // the callback will call the actual sendTo()
-            LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
-                      .arg(cur_zone_);
+            LOG_DEBUG(isc::resolve::logger,
+                      RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
+                .arg(cur_zone_);
 
             // Can we have multiple calls to nsas_out? Let's assume not
             // for now
@@ -544,10 +550,30 @@ private:
             }
 
             // Was a TCP query so we have received a packet over TCP with the
-            // TC bit set: report an error by dropping down to the common
+            // TC bit set: report an error by going to the common
             // error code.
+            goto SERVFAIL;
+
+        case isc::resolve::ResponseClassifier::RCODE:
+            // see if it's a FORMERR and a potential EDNS problem
+            if (incoming.getRcode() == Rcode::FORMERR()) {
+                if (protocol_ == IOFetch::UDP && edns_) {
+                    // try EDNS over TCP
+                    send(IOFetch::TCP, true);
+                    return (false);
+                } else if (protocol_ == IOFetch::TCP && edns_) {
+                    // try UDP, no EDNS
+                    send(IOFetch::UDP, false);
+                    return (false);
+                }
 
+                // TC should take care of non-EDNS over UDP, fall through to
+		// SERVFAIL if we get FORMERR instead
+            }
+            goto SERVFAIL;
+            
         default:
+SERVFAIL:
             // Some error in received packet it.  Report it and return SERVFAIL
             // to the caller.
             if (logger.isDebugEnabled()) {