Browse Source

[2157] add a testcase of truncated message

Yoshitaka Aharen 12 years ago
parent
commit
494784a813

+ 57 - 37
src/bin/auth/auth_srv.cc

@@ -100,17 +100,21 @@ namespace {
 // user of this class, so we hide it within the implementation.
 class RendererHolder {
 public:
-    RendererHolder(MessageRenderer& renderer, OutputBuffer* buffer) :
-        renderer_(renderer)
+    RendererHolder(MessageRenderer& renderer, OutputBuffer* buffer,
+                   MessageAttributes& stats_attrs) :
+        renderer_(renderer),
+        stats_attrs_(stats_attrs)
     {
         renderer.setBuffer(buffer);
     }
     ~RendererHolder() {
+        stats_attrs_.setResponseTruncated(renderer_.isTruncated());
         renderer_.setBuffer(NULL);
         renderer_.clear();
     }
 private:
     MessageRenderer& renderer_;
+    MessageAttributes& stats_attrs_;
 };
 
 // Similar to Renderer holder, this is a very basic RAII-style class
@@ -240,14 +244,18 @@ public:
     bool processNormalQuery(const IOMessage& io_message,
                             ConstEDNSPtr remote_edns, Message& message,
                             OutputBuffer& buffer,
-                            auto_ptr<TSIGContext> tsig_context);
+                            auto_ptr<TSIGContext> tsig_context,
+                            MessageAttributes& stats_attrs);
     bool processXfrQuery(const IOMessage& io_message, Message& message,
                          OutputBuffer& buffer,
-                         auto_ptr<TSIGContext> tsig_context);
+                         auto_ptr<TSIGContext> tsig_context,
+                         MessageAttributes& stats_attrs);
     bool processNotify(const IOMessage& io_message, Message& message,
                        OutputBuffer& buffer,
-                       auto_ptr<TSIGContext> tsig_context);
-    bool processUpdate(const IOMessage& io_message);
+                       auto_ptr<TSIGContext> tsig_context,
+                       MessageAttributes& stats_attrs);
+    bool processUpdate(const IOMessage& io_message,
+                       MessageAttributes& stats_attrs);
 
     IOService io_service_;
 
@@ -423,6 +431,7 @@ public:
 void
 makeErrorMessage(MessageRenderer& renderer, Message& message,
                  OutputBuffer& buffer, const Rcode& rcode,
+                 MessageAttributes& stats_attrs,
                  std::auto_ptr<TSIGContext> tsig_context =
                  std::auto_ptr<TSIGContext>())
 {
@@ -455,7 +464,7 @@ makeErrorMessage(MessageRenderer& renderer, Message& message,
 
     message.setRcode(rcode);
 
-    RendererHolder holder(renderer, &buffer);
+    RendererHolder holder(renderer, &buffer, stats_attrs);
     if (tsig_context.get() != NULL) {
         message.toWire(renderer, *tsig_context);
     } else {
@@ -526,13 +535,15 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
     } catch (const DNSProtocolError& error) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
                   .arg(error.getRcode().toText()).arg(error.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode());
+        makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode(),
+                         stats_attrs);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } catch (const Exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
                   .arg(ex.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     } // other exceptions will be handled at a higher layer.
@@ -561,7 +572,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
 
     if (tsig_error != TSIGError::NOERROR()) {
         makeErrorMessage(impl_->renderer_, message, buffer,
-                         tsig_error.toRcode(), tsig_context);
+                         tsig_error.toRcode(), stats_attrs, tsig_context);
         impl_->resumeServer(server, message, stats_attrs, true);
         return;
     }
@@ -581,44 +592,49 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
 
         if (opcode == Opcode::NOTIFY()) {
             send_answer = impl_->processNotify(io_message, message, buffer,
-                                               tsig_context);
+                                               tsig_context, stats_attrs);
         } else if (opcode == Opcode::UPDATE()) {
             if (impl_->ddns_forwarder_) {
-                send_answer = impl_->processUpdate(io_message);
+                send_answer = impl_->processUpdate(io_message, stats_attrs);
             } else {
                 makeErrorMessage(impl_->renderer_, message, buffer,
-                                 Rcode::NOTIMP(), tsig_context);
+                                 Rcode::NOTIMP(), stats_attrs, tsig_context);
             }
         } else if (opcode != Opcode::QUERY()) {
             LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_UNSUPPORTED_OPCODE)
                       .arg(message.getOpcode().toText());
             makeErrorMessage(impl_->renderer_, message, buffer,
-                             Rcode::NOTIMP(), tsig_context);
+                             Rcode::NOTIMP(), stats_attrs, tsig_context);
         } else if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
             makeErrorMessage(impl_->renderer_, message, buffer,
-                             Rcode::FORMERR(), tsig_context);
+                             Rcode::FORMERR(), stats_attrs, tsig_context);
         } else {
             ConstQuestionPtr question = *message.beginQuestion();
             const RRType& qtype = question->getType();
             if (qtype == RRType::AXFR()) {
                 send_answer = impl_->processXfrQuery(io_message, message,
-                                                     buffer, tsig_context);
+                                                     buffer, tsig_context,
+                                                     stats_attrs);
             } else if (qtype == RRType::IXFR()) {
                 send_answer = impl_->processXfrQuery(io_message, message,
-                                                     buffer, tsig_context);
+                                                     buffer, tsig_context,
+                                                     stats_attrs);
             } else {
                 send_answer = impl_->processNormalQuery(io_message, edns,
                                                         message, buffer,
-                                                        tsig_context);
+                                                        tsig_context,
+                                                        stats_attrs);
             }
         }
     } catch (const std::exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE)
                   .arg(ex.what());
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
     } catch (...) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE_UNKNOWN);
-        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
     }
     impl_->resumeServer(server, message, stats_attrs, send_answer);
 }
@@ -627,7 +643,8 @@ bool
 AuthSrvImpl::processNormalQuery(const IOMessage& io_message,
                                 ConstEDNSPtr remote_edns, Message& message,
                                 OutputBuffer& buffer,
-                                auto_ptr<TSIGContext> tsig_context)
+                                auto_ptr<TSIGContext> tsig_context,
+                                MessageAttributes& stats_attrs)
 {
     const bool dnssec_ok = remote_edns && remote_edns->getDNSSECAwareness();
     const uint16_t remote_bufsize = remote_edns ? remote_edns->getUDPSize() :
@@ -653,16 +670,18 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message,
             const Name& qname = question->getName();
             query_.process(*list, qname, qtype, message, dnssec_ok);
         } else {
-            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED());
+            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED(),
+                             stats_attrs);
             return (true);
         }
     } catch (const Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
-        makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL());
+        makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL(),
+                         stats_attrs);
         return (true);
     }
 
-    RendererHolder holder(renderer_, &buffer);
+    RendererHolder holder(renderer_, &buffer, stats_attrs);
     const bool udp_buffer =
         (io_message.getSocket().getProtocol() == IPPROTO_UDP);
     renderer_.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
@@ -679,12 +698,13 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message,
 bool
 AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
                              OutputBuffer& buffer,
-                             auto_ptr<TSIGContext> tsig_context)
+                             auto_ptr<TSIGContext> tsig_context,
+                             MessageAttributes& stats_attrs)
 {
     if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_UDP);
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -710,7 +730,7 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_ERROR)
                   .arg(err.what());
         makeErrorMessage(renderer_, message, buffer, Rcode::SERVFAIL(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -720,7 +740,8 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message,
 bool
 AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
                            OutputBuffer& buffer,
-                           std::auto_ptr<TSIGContext> tsig_context)
+                           std::auto_ptr<TSIGContext> tsig_context,
+                           MessageAttributes& stats_attrs)
 {
     // The incoming notify must contain exactly one question for SOA of the
     // zone name.
@@ -728,7 +749,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_NOTIFY_QUESTIONS)
                   .arg(message.getRRCount(Message::SECTION_QUESTION));
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
     ConstQuestionPtr question = *message.beginQuestion();
@@ -736,7 +757,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_NOTIFY_RRTYPE)
                   .arg(question->getType().toText());
         makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(),
-                         tsig_context);
+                         stats_attrs, tsig_context);
         return (true);
     }
 
@@ -794,7 +815,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     message.setHeaderFlag(Message::HEADERFLAG_AA);
     message.setRcode(Rcode::NOERROR());
 
-    RendererHolder holder(renderer_, &buffer);
+    RendererHolder holder(renderer_, &buffer, stats_attrs);
     if (tsig_context.get() != NULL) {
         message.toWire(renderer_, *tsig_context);
     } else {
@@ -804,7 +825,9 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
 }
 
 bool
-AuthSrvImpl::processUpdate(const IOMessage& io_message) {
+AuthSrvImpl::processUpdate(const IOMessage& io_message,
+                           MessageAttributes&)
+{
     // Push the update request to a separate process via the forwarder.
     // On successful push, the request shouldn't be responded from b10-auth,
     // so we return false.
@@ -816,10 +839,6 @@ void
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message,
                           MessageAttributes& stats_attrs,
                           const bool done) {
-    if (done) {
-        // isTruncated from MessageRenderer
-        stats_attrs.setResponseTruncated(renderer_.isTruncated());
-    }
     counters_.inc(stats_attrs, message, done);
     server->resume(done);
 }
@@ -870,7 +889,8 @@ void
 AuthSrv::createDDNSForwarder() {
     LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_START_DDNS_FORWARDER);
     impl_->ddns_forwarder_.reset(
-        new SocketSessionForwarderHolder("update", impl_->ddns_base_forwarder_));
+        new SocketSessionForwarderHolder("update",
+                                         impl_->ddns_base_forwarder_));
 }
 
 void

+ 28 - 4
src/bin/auth/tests/auth_srv_unittest.cc

@@ -1157,6 +1157,33 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
+TEST_F(AuthSrvTest, queryCounterTruncTest) {
+    // use CONFIG_TESTDB for large-rdata.example.com.
+    updateDatabase(&server, CONFIG_TESTDB);
+
+    // The counters should be initialized to 0.
+    ConstElementPtr stats_init = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    expectCounterItem(stats_init, "responses", 0);
+    expectCounterItem(stats_init, "qryauthans", 0);
+    expectCounterItem(stats_init->get("response"), "truncated", 0);
+
+    // Create UDP message and process.
+    // large-rdata.example.com. TXT; expect it exceeds 512 octet
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("large-rdata.example.com."),
+                                       RRClass::IN(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    ConstElementPtr stats_after = server.getStatistics()->
+        get("zones")->get("_SERVER_");
+    expectCounterItem(stats_after, "responses", 1);
+    expectCounterItem(stats_after, "qryauthans", 1);
+    expectCounterItem(stats_after->get("rcode"), "noerror", 1);
+    expectCounterItem(stats_after->get("response"), "truncated", 1);
+}
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     // Create UDP message and process.
@@ -1242,10 +1269,7 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
     createRequestPacket(request_message, IPPROTO_TCP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    // After processing the TCP query, these counters should be incremented:
-    //   request.tcp, opcode.query, rcode.refused, response
-    // and these counters should not be incremented:
-    //   request.udp
+
     ConstElementPtr stats_after = server.getStatistics()->
         get("zones")->get("_SERVER_");
     expectCounterItem(stats_after->get("request"), "udp", 0);

+ 8 - 0
src/lib/testutils/testdata/example.com

@@ -6,3 +6,11 @@ ns.example.com.	A 192.0.2.1
 ;; bogus RDATA for CNAME RR, but the loadzone tool accepts it.  looking up this
 ;; record will trigger an exception.
 broken.example.com. CNAME 0123456789012345678901234567890123456789012345678901234567890123456789.example.com.
+
+;; very large RDATA. it exceeds 512 octets.
+large-rdata.example.com. TXT "0-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "1-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "2-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "3-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "4-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+large-rdata.example.com. TXT "5-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"

BIN
src/lib/testutils/testdata/example.sqlite3