Browse Source

[1613] fix rcode counting, and add additional tests for that

Jelte Jansen 13 years ago
parent
commit
fe5b8226c1

+ 1 - 1
src/bin/auth/auth.spec.pre.in

@@ -344,7 +344,7 @@
         "item_optional": true,
         "item_optional": true,
         "item_default": 0,
         "item_default": 0,
         "item_title": "Sent 'no such rrset' response",
         "item_title": "Sent 'no such rrset' response",
-        "item_description": "The number of total responses with rcode 8 ()"
+        "item_description": "The number of total responses with rcode 8 (NXRRSET)"
       },
       },
       {
       {
         "item_name": "rcode.notauth",
         "item_name": "rcode.notauth",

+ 19 - 9
src/bin/auth/auth_srv.cc

@@ -409,13 +409,13 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
         // Ignore all responses.
         // Ignore all responses.
         if (message->getHeaderFlag(Message::HEADERFLAG_QR)) {
         if (message->getHeaderFlag(Message::HEADERFLAG_QR)) {
             LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_RECEIVED);
             LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_RECEIVED);
-            server->resume(false);
+            resumeServer(server, message, false);
             return;
             return;
         }
         }
     } catch (const Exception& ex) {
     } catch (const Exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_HEADER_PARSE_FAIL)
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_HEADER_PARSE_FAIL)
                   .arg(ex.what());
                   .arg(ex.what());
-        server->resume(false);
+        resumeServer(server, message, false);
         return;
         return;
     }
     }
 
 
@@ -426,13 +426,13 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR)
                   .arg(error.getRcode().toText()).arg(error.what());
                   .arg(error.getRcode().toText()).arg(error.what());
         makeErrorMessage(message, buffer, error.getRcode());
         makeErrorMessage(message, buffer, error.getRcode());
-        server->resume(true);
+        resumeServer(server, message, true);
         return;
         return;
     } catch (const Exception& ex) {
     } catch (const Exception& ex) {
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
         LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR)
                   .arg(ex.what());
                   .arg(ex.what());
         makeErrorMessage(message, buffer, Rcode::SERVFAIL());
         makeErrorMessage(message, buffer, Rcode::SERVFAIL());
-        server->resume(true);
+        resumeServer(server, message, true);
         return;
         return;
     } // other exceptions will be handled at a higher layer.
     } // other exceptions will be handled at a higher layer.
 
 
@@ -459,7 +459,7 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
 
 
     if (tsig_error != TSIGError::NOERROR()) {
     if (tsig_error != TSIGError::NOERROR()) {
         makeErrorMessage(message, buffer, tsig_error.toRcode(), tsig_context);
         makeErrorMessage(message, buffer, tsig_error.toRcode(), tsig_context);
-        server->resume(true);
+        resumeServer(server, message, true);
         return;
         return;
     }
     }
 
 
@@ -492,10 +492,7 @@ AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
         }
         }
     }
     }
 
 
-    // update per rcode statistics counter.
-    impl_->counters_.inc(message->getRcode());
-
-    server->resume(send_answer);
+    resumeServer(server, message, send_answer);
 }
 }
 
 
 bool
 bool
@@ -786,6 +783,11 @@ AuthSrv::getCounter(const Opcode opcode) const {
     return (impl_->counters_.getCounter(opcode));
     return (impl_->counters_.getCounter(opcode));
 }
 }
 
 
+uint64_t
+AuthSrv::getCounter(const Rcode rcode) const {
+    return (impl_->counters_.getCounter(rcode));
+}
+
 const AddressList&
 const AddressList&
 AuthSrv::getListenAddresses() const {
 AuthSrv::getListenAddresses() const {
     return (impl_->listen_addresses_);
     return (impl_->listen_addresses_);
@@ -805,3 +807,11 @@ void
 AuthSrv::setTSIGKeyRing(const boost::shared_ptr<TSIGKeyRing>* keyring) {
 AuthSrv::setTSIGKeyRing(const boost::shared_ptr<TSIGKeyRing>* keyring) {
     impl_->keyring_ = keyring;
     impl_->keyring_ = keyring;
 }
 }
+
+void
+AuthSrv::resumeServer(DNSServer* server, MessagePtr message, bool done) {
+    if (done) {
+        impl_->counters_.inc(message->getRcode());
+    }
+    server->resume(done);
+}

+ 30 - 0
src/bin/auth/auth_srv.h

@@ -361,6 +361,20 @@ public:
     /// \return the value of the counter.
     /// \return the value of the counter.
     uint64_t getCounter(const isc::dns::Opcode opcode) const;
     uint64_t getCounter(const isc::dns::Opcode opcode) const;
 
 
+    /// \brief Get the value of per Rcode counter in the Auth Counters.
+    ///
+    /// This function calls AuthCounters::getCounter(isc::dns::Rcode) and
+    /// returns its return value.
+    ///
+    /// \note This is a tentative interface as an attempt of experimentally
+    /// supporting more statistics counters.  This should eventually be more
+    /// generalized.  In any case, this method is mainly for testing.
+    ///
+    /// \throw None
+    /// \param rcode The rcode of the counter to get the value of
+    /// \return the value of the counter.
+    uint64_t getCounter(const isc::dns::Rcode rcode) const;
+
     /**
     /**
      * \brief Set and get the addresses we listen on.
      * \brief Set and get the addresses we listen on.
      */
      */
@@ -382,6 +396,22 @@ public:
                         keyring);
                         keyring);
 
 
 private:
 private:
+    /// \brief Resume the server
+    ///
+    /// This is a wrapper call for DNSServer::resume(done), if 'done' is true,
+    /// the Rcode set in the given Message is counted in the statistics
+    /// counter.
+    ///
+    /// This method is expected to be called by processMessage()
+    ///
+    /// \param server The DNSServer as passed to processMessage()
+    /// \param message The response as constructed by processMessage()
+    /// \param done If true, the Rcode from the given message is counted,
+    ///             this value is then passed to server->resume(bool)
+    void resumeServer(isc::asiodns::DNSServer* server,
+                      isc::dns::MessagePtr message,
+                      bool done);
+
     AuthSrvImpl* impl_;
     AuthSrvImpl* impl_;
     isc::asiolink::SimpleCallback* checkin_;
     isc::asiolink::SimpleCallback* checkin_;
     isc::asiodns::DNSLookup* dns_lookup_;
     isc::asiodns::DNSLookup* dns_lookup_;

+ 56 - 0
src/bin/auth/tests/auth_srv_unittest.cc

@@ -84,6 +84,32 @@ protected:
         server.processMessage(*io_message, parse_message, response_obuffer,
         server.processMessage(*io_message, parse_message, response_obuffer,
                               &dnsserv);
                               &dnsserv);
     }
     }
+
+    // Helper for checking Rcode statistic counters
+    void checkRcodeCounter(const Rcode& rcode, int expected_value) {
+        EXPECT_EQ(expected_value, server.getCounter(rcode)) <<
+                  "Expected Rcode count for " << rcode.toText() <<
+                  " " << expected_value << ", was: " <<
+                  server.getCounter(rcode);
+    }
+    // Checks whether all Rcode counters are set to zero
+    void checkAllRcodeCountersZero() {
+        for (int i = 0; i < 17; i++) {
+            checkRcodeCounter(Rcode(i), 0);
+        }
+    }
+    // Checks whether all Rcode counters are set to zero except the given
+    // rcode (it is checked to be set to 'value')
+    void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) {
+        for (int i = 0; i < 17; i++) {
+            const Rcode rc(i);
+            if (rc == rcode) {
+                checkRcodeCounter(Rcode(i), value);
+            } else {
+                checkRcodeCounter(Rcode(i), 0);
+            }
+        }
+    }
     IOService ios_;
     IOService ios_;
     DNSService dnss_;
     DNSService dnss_;
     MockSession statistics_session;
     MockSession statistics_session;
@@ -145,6 +171,7 @@ TEST_F(AuthSrvTest, builtInQuery) {
                         response_obuffer->getData(),
                         response_obuffer->getData(),
                         response_obuffer->getLength(),
                         response_obuffer->getLength(),
                         &response_data[0], response_data.size());
                         &response_data[0], response_data.size());
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
 }
 }
 
 
 // Same test emulating the UDPServer class behavior (defined in libasiolink).
 // Same test emulating the UDPServer class behavior (defined in libasiolink).
@@ -195,38 +222,46 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
 // Unsupported requests.  Should result in NOTIMP.
 // Unsupported requests.  Should result in NOTIMP.
 TEST_F(AuthSrvTest, unsupportedRequest) {
 TEST_F(AuthSrvTest, unsupportedRequest) {
     unsupportedRequest();
     unsupportedRequest();
+    // unsupportedRequest tries 14 different opcodes
+    checkAllRcodeCountersZeroExcept(Rcode::NOTIMP(), 14);
 }
 }
 
 
 // Multiple questions.  Should result in FORMERR.
 // Multiple questions.  Should result in FORMERR.
 TEST_F(AuthSrvTest, multiQuestion) {
 TEST_F(AuthSrvTest, multiQuestion) {
     multiQuestion();
     multiQuestion();
+    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
 }
 }
 
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
 TEST_F(AuthSrvTest, shortMessage) {
     shortMessage();
     shortMessage();
+    checkAllRcodeCountersZero();
 }
 }
 
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // Response messages.  Must be silently dropped, whether it's a valid response
 // or malformed or could otherwise cause a protocol error.
 // or malformed or could otherwise cause a protocol error.
 TEST_F(AuthSrvTest, response) {
 TEST_F(AuthSrvTest, response) {
     response();
     response();
+    checkAllRcodeCountersZero();
 }
 }
 
 
 // Query with a broken question
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
 TEST_F(AuthSrvTest, shortQuestion) {
     shortQuestion();
     shortQuestion();
+    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
 }
 }
 
 
 // Query with a broken answer section
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
 TEST_F(AuthSrvTest, shortAnswer) {
     shortAnswer();
     shortAnswer();
+    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
 }
 }
 
 
 // Query with unsupported version of EDNS.
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
 TEST_F(AuthSrvTest, ednsBadVers) {
     ednsBadVers();
     ednsBadVers();
+    checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
 }
 }
 
 
 TEST_F(AuthSrvTest, AXFROverUDP) {
 TEST_F(AuthSrvTest, AXFROverUDP) {
@@ -244,6 +279,7 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
     server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
     server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
     EXPECT_FALSE(dnsserv.hasAnswer());
     EXPECT_FALSE(dnsserv.hasAnswer());
     EXPECT_TRUE(xfrout.isConnected());
     EXPECT_TRUE(xfrout.isConnected());
+    checkAllRcodeCountersZero();
 }
 }
 
 
 // Try giving the server a TSIG signed request and see it can anwer signed as
 // Try giving the server a TSIG signed request and see it can anwer signed as
@@ -279,6 +315,8 @@ TEST_F(AuthSrvTest, TSIGSigned) {
                                    response_obuffer->getLength()));
                                    response_obuffer->getLength()));
     EXPECT_EQ(TSIGError::NOERROR(), error) <<
     EXPECT_EQ(TSIGError::NOERROR(), error) <<
         "The server signed the response, but it doesn't seem to be valid";
         "The server signed the response, but it doesn't seem to be valid";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
 }
 }
 
 
 // Give the server a signed request, but don't give it the key. It will
 // Give the server a signed request, but don't give it the key. It will
@@ -311,6 +349,8 @@ TEST_F(AuthSrvTest, TSIGSignedBadKey) {
     EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
     EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
         "It should be unsigned with this error";
         "It should be unsigned with this error";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
 }
 }
 
 
 // Give the server a signed request, but signed by a different key
 // Give the server a signed request, but signed by a different key
@@ -344,6 +384,8 @@ TEST_F(AuthSrvTest, TSIGBadSig) {
     EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
     EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
     EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
         "It should be unsigned with this error";
         "It should be unsigned with this error";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
 }
 }
 
 
 // Give the server a signed unsupported request with a bad signature.
 // Give the server a signed unsupported request with a bad signature.
@@ -383,6 +425,8 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
     // TSIG should have failed, and so the per opcode counter shouldn't be
     // TSIG should have failed, and so the per opcode counter shouldn't be
     // incremented.
     // incremented.
     EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
     EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
 }
 }
 
 
 TEST_F(AuthSrvTest, AXFRConnectFail) {
 TEST_F(AuthSrvTest, AXFRConnectFail) {
@@ -531,6 +575,8 @@ TEST_F(AuthSrvTest, notify) {
     EXPECT_EQ(Name("example.com"), question->getName());
     EXPECT_EQ(Name("example.com"), question->getName());
     EXPECT_EQ(RRClass::IN(), question->getClass());
     EXPECT_EQ(RRClass::IN(), question->getClass());
     EXPECT_EQ(RRType::SOA(), question->getType());
     EXPECT_EQ(RRType::SOA(), question->getType());
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
 }
 }
 
 
 TEST_F(AuthSrvTest, notifyForCHClass) {
 TEST_F(AuthSrvTest, notifyForCHClass) {
@@ -799,6 +845,10 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
                           &dnsserv);
                           &dnsserv);
     // After processing UDP query, the counter should be 1.
     // After processing UDP query, the counter should be 1.
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
+    // The counter for SUCCESS responses should also be one
+    EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
+    // The counter for REFUSED responses should also be one, the rest zero
+    checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
 }
 }
 
 
 // Submit TCP normal query and check query counter
 // Submit TCP normal query and check query counter
@@ -814,6 +864,10 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
                           &dnsserv);
                           &dnsserv);
     // After processing TCP query, the counter should be 1.
     // After processing TCP query, the counter should be 1.
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // The counter for SUCCESS responses should also be one
+    EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
+    // The counter for REFUSED responses should also be one, the rest zero
+    checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
 }
 }
 
 
 // Submit TCP AXFR query and check query counter
 // Submit TCP AXFR query and check query counter
@@ -829,6 +883,8 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
     EXPECT_FALSE(dnsserv.hasAnswer());
     EXPECT_FALSE(dnsserv.hasAnswer());
     // After processing TCP AXFR query, the counter should be 1.
     // After processing TCP AXFR query, the counter should be 1.
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
     EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    // No rcodes should be incremented
+    checkAllRcodeCountersZero();
 }
 }
 
 
 // Submit TCP IXFR query and check query counter
 // Submit TCP IXFR query and check query counter