diff --git a/doc/sphinx/arm/ddns.rst b/doc/sphinx/arm/ddns.rst index afefb6d29e63f4851166df35923c72c2f76eea9f..a108b3974093c3686989f30916ddeff69b949014 100644 --- a/doc/sphinx/arm/ddns.rst +++ b/doc/sphinx/arm/ddns.rst @@ -298,6 +298,14 @@ The D2 server supports the following operational commands: - status-get - version-get +Starting with Kea version 2.0.0 the D2 server supports too the following +operational commands for statistics: + +- statistic-get +- statistic-get-all +- statistic-reset +- statistic-reset-all + The ``shutdown`` command supports the extra ``type`` argument which controls the way the D2 server cleans up on exit. The supported shutdown types are: @@ -908,6 +916,67 @@ These Reverse DDNS Domains are specified as follows: } } +DHCP-DDNS Server Statistics +=========================== + +Kea version 2.0.0 introduced statistics support for the DHCP-DDNS. + +Statistics are divided in three groups: Name Change Request, DNS update +and per TSIG key DNS updates. If the statistics of the first two groups +are cumulative, i.e. not affected by configuration change or reload, +per key statistics are reset to 0 when the underlying object is +(re)created. + +Currently the statistics management is limited: + +- only integer samples (i.e. a counter and a timestamp) are used +- the maximum sample count is 1 +- there is no API to remove one or all statistics +- there is no API to set the maximum sample count or age + +.. note:: + + Hook libraries like the GSS-TSIG add new statistics. + +A reference about Kea statistics can be found at :ref:`stats`. + +NCR Statistics +-------------- + +The Name Change Request statistics are: + +- ``ncr-received`` - received valid NCRs +- ``ncr-invalid`` - received invalid NCRs +- ``ncr-error`` - errors in NCR receptions other than I/O cancel on shutdown + +DNS Update Statistics +--------------------- + +The global DNS update statistics are: + +- ``update-sent`` - sent DNS updates +- ``update-signed`` - sent DNS updates protected by TSIG +- ``update-unsigned`` - sent DNS updates not protected by TSIG +- ``update-success`` - DNS updates which completed with a success +- ``update-timeout`` - DNS updates which completed on timeout +- ``update-error`` - DNS updates which completed with an error other than + timeout + +Per TSIG key DNS Update Statistics +---------------------------------- + +The per TSIG key DNS update statistics are: + +- ``update-sent`` - sent DNS updates +- ``update-success`` - DNS updates which completed with a success +- ``update-timeout`` - DNS updates which completed on timeout +- ``update-error`` - DNS updates which completed with an error other than + timeout + +The name of a per key statistics is ``key[].``, +for instance the name of the ``update-sent`` statistics for the +``key.example.com.`` TSIG key is ``key[key.example.com.].update-sent``. + DHCP-DDNS Server Limitations ============================ diff --git a/src/bin/d2/d2_controller.cc b/src/bin/d2/d2_controller.cc index dc31b552b7676d387e5ccc71f8a40afdffde83ae..60f24eb473ffcf47800366f392601c7338f9d904 100644 --- a/src/bin/d2/d2_controller.cc +++ b/src/bin/d2/d2_controller.cc @@ -11,11 +11,13 @@ #include #include #include +#include #include using namespace isc::config; using namespace isc::process; +using namespace isc::stats; namespace ph = std::placeholders; namespace isc { @@ -80,6 +82,19 @@ D2Controller::registerCommands() { CommandMgr::instance().registerCommand(VERSION_GET_COMMAND, std::bind(&D2Controller::versionGetHandler, this, ph::_1, ph::_2)); + + // Register statistic related commands. + CommandMgr::instance().registerCommand("statistic-get", + std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2)); + + CommandMgr::instance().registerCommand("statistic-get-all", + std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2)); + + CommandMgr::instance().registerCommand("statistic-reset", + std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2)); + + CommandMgr::instance().registerCommand("statistic-reset-all", + std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2)); } void @@ -96,6 +111,10 @@ D2Controller::deregisterCommands() { CommandMgr::instance().deregisterCommand(CONFIG_TEST_COMMAND); CommandMgr::instance().deregisterCommand(CONFIG_WRITE_COMMAND); CommandMgr::instance().deregisterCommand(SHUT_DOWN_COMMAND); + CommandMgr::instance().deregisterCommand("statistic-get"); + CommandMgr::instance().deregisterCommand("statistic-get-all"); + CommandMgr::instance().deregisterCommand("statistic-reset"); + CommandMgr::instance().deregisterCommand("statistic-reset-all"); CommandMgr::instance().deregisterCommand(STATUS_GET_COMMAND); CommandMgr::instance().deregisterCommand(VERSION_GET_COMMAND); @@ -104,8 +123,6 @@ D2Controller::deregisterCommands() { } } - - isc::data::ConstElementPtr D2Controller::parseFile(const std::string& file_name) { isc::data::ConstElementPtr elements; @@ -135,5 +152,5 @@ D2Controller::getVersionAddendum() { } -}; // end namespace isc::d2 -}; // end namespace isc +} // end namespace isc::d2 +} // end namespace isc diff --git a/src/bin/d2/d2_hooks.dox b/src/bin/d2/d2_hooks.dox index 8ef06a9b182c1e45cb5977641ef8b21bd3454824..0c33820b8f8780b6c54951eca5ee929507745f21 100644 --- a/src/bin/d2/d2_hooks.dox +++ b/src/bin/d2/d2_hooks.dox @@ -69,7 +69,7 @@ to the end of this list. @subsection d2HooksSelectKey select_key - @b Arguments: - name: @b current_server, type: isc::d2::DnsServerInfoPtr, direction: in - - name: @b tsig_key, type: isc::dns::TSIGKeyPtr, direction: in/out + - name: @b tsig_key, type: isc::d2::D2TsigKeyPtr, direction: in/out - @b Description: this callout is executed when the D2 is selecting for a TSIG key to protect the next DNS update to the already chosen DNS diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc index 973e98e24838107d1af7d6733f19dd6fb919466d..ebd3865e79009b02bcb17fa3cc5ceafc32b31657 100644 --- a/src/bin/d2/d2_process.cc +++ b/src/bin/d2/d2_process.cc @@ -12,8 +12,11 @@ #include #include #include +#include +#include #include #include +#include using namespace isc::hooks; using namespace isc::process; @@ -44,7 +47,7 @@ namespace d2 { // Setting to 80% for now. This is an arbitrary choice and should probably // be configurable. -const unsigned int D2Process::QUEUE_RESTART_PERCENT = 80; +const unsigned int D2Process::QUEUE_RESTART_PERCENT = 80; D2Process::D2Process(const char* name, const asiolink::IOServicePtr& io_service) : DProcessBase(name, io_service, DCfgMgrBasePtr(new D2CfgMgr())), @@ -61,7 +64,18 @@ D2Process::D2Process(const char* name, const asiolink::IOServicePtr& io_service) // Pass in both queue manager and configuration manager. // Pass in IOService for DNS update transaction IO event processing. D2CfgMgrPtr tmp = getD2CfgMgr(); - update_mgr_.reset(new D2UpdateMgr(queue_mgr_, tmp, getIoService())); + update_mgr_.reset(new D2UpdateMgr(queue_mgr_, tmp, getIoService())); + + // Instantiate stats manager. + // Initialize statistics. + isc::stats::StatsMgr& stats_mgr = isc::stats::StatsMgr::instance(); + stats_mgr.setMaxSampleCountDefault(0); + for (const auto& name : D2Stats::ncr) { + stats_mgr.setValue(name, static_cast(0)); + } + for (const auto& name : D2Stats::update) { + stats_mgr.setValue(name, static_cast(0)); + } }; void @@ -89,7 +103,7 @@ D2Process::run() { // process finished ones. update_mgr_->sweep(); - // Wait on IO event(s) - block until one or more of the following + // Wait on IO event(s) - block until one or more of the following // has occurred: // a. NCR message has been received // b. Transaction IO has completed @@ -111,9 +125,9 @@ D2Process::run() { "Process run method failed: " << ex.what()); } - // @todo - if queue isn't empty, we may need to persist its contents - // this might be the place to do it, once there is a persistence mgr. - // This may also be better in checkQueueStatus. + /// @todo - if queue isn't empty, we may need to persist its contents + /// this might be the place to do it, once there is a persistence mgr. + /// This may also be better in checkQueueStatus. controller->deregisterCommands(); @@ -133,7 +147,7 @@ D2Process::runIO() { // method. This is a handy method which runs all ready handlers without // blocking. asiolink::IOServicePtr& io = getIoService(); - boost::asio::io_service& asio_io_service = io->get_io_service(); + boost::asio::io_service& asio_io_service = io->get_io_service(); // Poll runs all that are ready. If none are ready it returns immediately // with a count of zero. @@ -261,9 +275,9 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) { // the method we are in now is invoked as part of the configuration event // callback. This means you can't wait for events here, you are already // in one. - // (@todo NOTE This could be turned into a bitmask of flags if we find other - // things that need reconfiguration. It might also be useful if we - // did some analysis to decide what if anything we need to do.) + /// (@todo NOTE This could be turned into a bitmask of flags if we find other + /// things that need reconfiguration. It might also be useful if we + /// did some analysis to decide what if anything we need to do.) reconf_queue_flag_ = true; // This hook point notifies hooks libraries that the configuration of the @@ -306,10 +320,10 @@ D2Process::checkQueueStatus() { switch (queue_mgr_->getMgrState()){ case D2QueueMgr::RUNNING: if (reconf_queue_flag_ || shouldShutdown()) { - // If we need to reconfigure the queue manager or we have been - // told to shutdown, then stop listening first. Stopping entails - // canceling active listening which may generate an IO event, so - // instigate the stop and get out. + /// If we need to reconfigure the queue manager or we have been + /// told to shutdown, then stop listening first. Stopping entails + /// canceling active listening which may generate an IO event, so + /// instigate the stop and get out. try { LOG_DEBUG(d2_logger, isc::log::DBGLVL_START_SHUT, DHCP_DDNS_QUEUE_MGR_STOPPING) @@ -325,9 +339,9 @@ D2Process::checkQueueStatus() { break; case D2QueueMgr::STOPPED_QUEUE_FULL: { - // Resume receiving once the queue has decreased by twenty - // percent. This is an arbitrary choice. @todo this value should - // probably be configurable. + /// Resume receiving once the queue has decreased by twenty + /// percent. This is an arbitrary choice. + /// @todo this value should probably be configurable. size_t threshold = (((queue_mgr_->getMaxQueueSize() * QUEUE_RESTART_PERCENT)) / 100); if (queue_mgr_->getQueueSize() <= threshold) { @@ -345,13 +359,13 @@ D2Process::checkQueueStatus() { } case D2QueueMgr::STOPPED_RECV_ERROR: - // If the receive error is not due to some fallout from shutting - // down then we will attempt to recover by reconfiguring the listener. - // This will close and destruct the current listener and make a new - // one with new resources. - // @todo This may need a safety valve such as retry count or a timer - // to keep from endlessly retrying over and over, with little time - // in between. + /// If the receive error is not due to some fallout from shutting + /// down then we will attempt to recover by reconfiguring the listener. + /// This will close and destruct the current listener and make a new + /// one with new resources. + /// @todo This may need a safety valve such as retry count or a timer + /// to keep from endlessly retrying over and over, with little time + /// in between. if (!shouldShutdown()) { LOG_INFO (d2_logger, DHCP_DDNS_QUEUE_MGR_RECOVERING); reconfigureQueueMgr(); @@ -359,10 +373,10 @@ D2Process::checkQueueStatus() { break; case D2QueueMgr::STOPPING: - // We are waiting for IO to cancel, so this is a NOP. - // @todo Possible timer for self-defense? We could conceivably - // get into a condition where we never get the event, which would - // leave us stuck in stopping. This is hugely unlikely but possible? + /// We are waiting for IO to cancel, so this is a NOP. + /// @todo Possible timer for self-defense? We could conceivably + /// get into a condition where we never get the event, which would + /// leave us stuck in stopping. This is hugely unlikely but possible? break; default: @@ -386,9 +400,9 @@ D2Process::reconfigureQueueMgr() { // queue manager in INITTED state, which is fine. // What we don't want is to continually attempt to reconfigure so set // the flag false now. - // @todo This method assumes only 1 type of listener. This will change - // to support at least a TCP version, possibly some form of RDBMS listener - // as well. + /// @todo This method assumes only 1 type of listener. This will change + /// to support at least a TCP version, possibly some form of RDBMS listener + /// as well. reconf_queue_flag_ = false; try { // Wipe out the current listener. @@ -397,9 +411,9 @@ D2Process::reconfigureQueueMgr() { // Get the configuration parameters that affect Queue Manager. const D2ParamsPtr& d2_params = getD2CfgMgr()->getD2Params(); - // Warn the user if the server address is not the loopback. + /// Warn the user if the server address is not the loopback. /// @todo Remove this once we provide a secure mechanism. - std::string ip_address = d2_params->getIpAddress().toText(); + std::string ip_address = d2_params->getIpAddress().toText(); if (ip_address != "127.0.0.1" && ip_address != "::1") { LOG_WARN(d2_logger, DHCP_DDNS_NOT_ON_LOOPBACK).arg(ip_address); } @@ -418,8 +432,9 @@ D2Process::reconfigureQueueMgr() { } // Now start it. This assumes that starting is a synchronous, - // blocking call that executes quickly. @todo Should that change then - // we will have to expand the state model to accommodate this. + // blocking call that executes quickly. + /// @todo Should that change then we will have to expand the state model + /// to accommodate this. queue_mgr_->startListening(); } catch (const isc::Exception& ex) { // Queue manager failed to initialize and therefore not listening. diff --git a/src/bin/d2/d2_update_mgr.h b/src/bin/d2/d2_update_mgr.h index a06d787dccaeb02e49be87adaa9b23789c67bf51..2ff8765bcd339cde76b2ff42a20e6d3ca54d8f1d 100644 --- a/src/bin/d2/d2_update_mgr.h +++ b/src/bin/d2/d2_update_mgr.h @@ -69,18 +69,6 @@ public: /// implementation. static const size_t MAX_TRANSACTIONS_DEFAULT = 32; - // @todo This structure is not yet used. It is here in anticipation of - // enabled statistics capture. - struct Stats { - uint64_t start_time_; - uint64_t stop_time_; - uint64_t update_count_; - uint64_t min_update_time_; - uint64_t max_update_time_; - uint64_t server_rejects_; - uint64_t server_timeouts_; - }; - /// @brief Constructor /// /// @param queue_mgr reference to the queue manager receiving requests diff --git a/src/bin/d2/dns_client.cc b/src/bin/d2/dns_client.cc index 1d4e4d62c8d5c5f26556c5d417614b55b61b5422..5aaddd6474cf0e8f4827da7e10908b2e6fa64b53 100644 --- a/src/bin/d2/dns_client.cc +++ b/src/bin/d2/dns_client.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace isc { @@ -26,6 +27,7 @@ using namespace isc::util; using namespace isc::asiolink; using namespace isc::asiodns; using namespace isc::dns; +using namespace isc::stats; // This class provides the implementation for the DNSClient. This allows for // the separation of the DNSClient interface from the implementation details. @@ -55,6 +57,8 @@ public: DNSClient::Protocol proto_; // TSIG context used to sign outbound and verify inbound messages. dns::TSIGContextPtr tsig_context_; + // TSIG key name for stats. + std::string tsig_key_name_; // Constructor and Destructor DNSClientImpl(D2UpdateMessagePtr& response_placeholder, @@ -74,10 +78,13 @@ public: const uint16_t ns_port, D2UpdateMessage& update, const unsigned int wait, - const dns::TSIGKeyPtr& tsig_key); + const D2TsigKeyPtr& tsig_key); // This function maps the IO error to the DNSClient error. DNSClient::Status getStatus(const asiodns::IOFetch::Result); + + // This function updates statistics. + void incrStats(const std::string& stat, bool update_key = true); }; DNSClientImpl::DNSClientImpl(D2UpdateMessagePtr& response_placeholder, @@ -137,17 +144,22 @@ DNSClientImpl::operator()(asiodns::IOFetch::Result result) { try { response_->fromWire(in_buf_->getData(), in_buf_->getLength(), tsig_context_.get()); + incrStats("update-success"); } catch (const isc::Exception& ex) { status = DNSClient::INVALID_RESPONSE; LOG_DEBUG(d2_to_dns_logger, isc::log::DBGLVL_TRACE_DETAIL, DHCP_DDNS_INVALID_RESPONSE).arg(ex.what()); - + incrStats("update-error"); } if (tsig_context_) { // Context is a one-shot deal, get rid of it. tsig_context_.reset(); } + } else if (status == DNSClient::TIMEOUT) { + incrStats("update-timeout"); + } else { + incrStats("update-error"); } // Once we are done with internal business, let's call a callback supplied @@ -174,13 +186,14 @@ DNSClientImpl::getStatus(const asiodns::IOFetch::Result result) { } return (DNSClient::OTHER); } + void DNSClientImpl::doUpdate(asiolink::IOService& io_service, const IOAddress& ns_addr, const uint16_t ns_port, D2UpdateMessage& update, const unsigned int wait, - const dns::TSIGKeyPtr& tsig_key) { + const D2TsigKeyPtr& tsig_key) { // The underlying implementation which we use to send DNS Updates uses // signed integers for timeout. If we want to avoid overflows we need to // respect this limitation here. @@ -195,8 +208,10 @@ DNSClientImpl::doUpdate(asiolink::IOService& io_service, // that TSIG should be used. if (tsig_key) { tsig_context_.reset(new TSIGContext(*tsig_key)); + tsig_key_name_ = tsig_key->getKeyName().toText(); } else { tsig_context_.reset(); + tsig_key_name_.clear(); } // A renderer is used by the toWire function which creates the on-wire data @@ -227,6 +242,24 @@ DNSClientImpl::doUpdate(asiolink::IOService& io_service, // Post the task to the task queue in the IO service. Caller will actually // run these tasks by executing IOService::run. io_service.post(io_fetch); + + // Update sent statistics. + incrStats("update-sent"); + if (tsig_key) { + incrStats("update-signed", false); + } else { + incrStats("update-unsigned", false); + } +} + +void +DNSClientImpl::incrStats(const std::string& stat, bool update_key) { + StatsMgr& mgr = StatsMgr::instance(); + mgr.addValue(stat, static_cast(1)); + if (update_key && !tsig_key_name_.empty()) { + mgr.addValue(StatsMgr::generateName("key", tsig_key_name_, stat), + static_cast(1)); + } } DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder, @@ -250,7 +283,7 @@ DNSClient::doUpdate(asiolink::IOService& io_service, const uint16_t ns_port, D2UpdateMessage& update, const unsigned int wait, - const dns::TSIGKeyPtr& tsig_key) { + const D2TsigKeyPtr& tsig_key) { impl_->doUpdate(io_service, ns_addr, ns_port, update, wait, tsig_key); } diff --git a/src/bin/d2/dns_client.h b/src/bin/d2/dns_client.h index 41423be88946fb9955c86af6182a9a54b03e41ee..fb2412523d78eb8705b62fec08e80c815d2b56cd 100644 --- a/src/bin/d2/dns_client.h +++ b/src/bin/d2/dns_client.h @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,7 +13,7 @@ #include #include -#include +#include namespace isc { namespace d2 { @@ -138,7 +138,7 @@ public: /// @param wait A timeout (in milliseconds) for the response. If a response /// is not received within the timeout, exchange is interrupted. This value /// must not exceed maximal value for 'int' data type. - /// @param tsig_key A pointer to an @c isc::dns::TSIGKey object that will + /// @param tsig_key A pointer to an @c D2TsigKeyPtr object that will /// (if not null) be used to sign the DNS Update message and verify the /// response. void doUpdate(asiolink::IOService& io_service, @@ -146,7 +146,7 @@ public: const uint16_t ns_port, D2UpdateMessage& update, const unsigned int wait, - const dns::TSIGKeyPtr& tsig_key = dns::TSIGKeyPtr()); + const D2TsigKeyPtr& tsig_key = D2TsigKeyPtr()); private: DNSClientImpl* impl_; ///< Pointer to DNSClient implementation. diff --git a/src/bin/d2/nc_trans.h b/src/bin/d2/nc_trans.h index a25b5da57f3364f3f767a3ed904b95fcfd4e9f47..503d9a0f83a870f1aeeec47fe784fb8ebe927417 100644 --- a/src/bin/d2/nc_trans.h +++ b/src/bin/d2/nc_trans.h @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -589,7 +589,7 @@ private: D2CfgMgrPtr cfg_mgr_; /// @brief Pointer to the TSIG key which should be used (if any). - dns::TSIGKeyPtr tsig_key_; + D2TsigKeyPtr tsig_key_; }; /// @brief Defines a pointer to a NameChangeTransaction. diff --git a/src/bin/d2/tests/d2_command_unittest.cc b/src/bin/d2/tests/d2_command_unittest.cc index 5192e7831bbb862d748ec72bf6a7df3dd363b3c3..8f956e79abfeecc641d82425afc9fea275322ecc 100644 --- a/src/bin/d2/tests/d2_command_unittest.cc +++ b/src/bin/d2/tests/d2_command_unittest.cc @@ -540,6 +540,10 @@ TEST_F(CtrlChannelD2Test, commandsRegistration) { EXPECT_TRUE(command_list.find("\"config-write\"") != string::npos); EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos); EXPECT_TRUE(command_list.find("\"status-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos); + EXPECT_TRUE(command_list.find("\"statistic-reset\"") != string::npos); + EXPECT_TRUE(command_list.find("\"statistic-reset-all\"") != string::npos); EXPECT_TRUE(command_list.find("\"version-get\"") != string::npos); // Ok, and now delete the server. It should deregister its commands. @@ -628,6 +632,11 @@ TEST_F(CtrlChannelD2Test, listCommands) { checkListCommands(rsp, "config-test"); checkListCommands(rsp, "config-write"); checkListCommands(rsp, "list-commands"); + checkListCommands(rsp, "statistic-get"); + checkListCommands(rsp, "statistic-get-all"); + checkListCommands(rsp, "statistic-reset"); + checkListCommands(rsp, "statistic-reset-all"); + checkListCommands(rsp, "status-get"); checkListCommands(rsp, "shutdown"); checkListCommands(rsp, "version-get"); } diff --git a/src/bin/d2/tests/d2_simple_parser_unittest.cc b/src/bin/d2/tests/d2_simple_parser_unittest.cc index 57777ec3f31e7cba71b1f0019f63aa8a172b29da..b236469cb9e27c8f80527c227f4282a5b269f4b3 100644 --- a/src/bin/d2/tests/d2_simple_parser_unittest.cc +++ b/src/bin/d2/tests/d2_simple_parser_unittest.cc @@ -641,7 +641,7 @@ TEST_F(TSIGKeyInfoParserTest, invalidEntry) { " \"digest-bits\": 120 , " " \"secret\": \"bogus\" " "}"; - PARSE_FAIL(config, "Cannot make TSIGKey: Incomplete input for base64:" + PARSE_FAIL(config, "Cannot make D2TsigKey: Incomplete input for base64:" " bogus (:1:1)"); } diff --git a/src/bin/d2/tests/d2_update_message_unittests.cc b/src/bin/d2/tests/d2_update_message_unittests.cc index 1320e377a36c0bf1cca0ef58919029c4e089df64..092b23f9e60b2cce060e76b4781678d27b3408b3 100644 --- a/src/bin/d2/tests/d2_update_message_unittests.cc +++ b/src/bin/d2/tests/d2_update_message_unittests.cc @@ -583,18 +583,18 @@ TEST_F(D2UpdateMessageTest, toWireInvalidQRFlag) { TEST_F(D2UpdateMessageTest, validTSIG) { // Create a TSIG Key and context std::string secret("this key will match"); - TSIGKeyPtr right_key; + D2TsigKeyPtr right_key; ASSERT_NO_THROW(right_key.reset(new - TSIGKey(Name("right.com"), - TSIGKey::HMACMD5_NAME(), - secret.c_str(), secret.size()))); + D2TsigKey(Name("right.com"), + TSIGKey::HMACMD5_NAME(), + secret.c_str(), secret.size()))); - TSIGKeyPtr wrong_key; + D2TsigKeyPtr wrong_key; secret = "this key will not match"; ASSERT_NO_THROW(wrong_key.reset(new - TSIGKey(Name("wrong.com"), - TSIGKey::HMACMD5_NAME(), - secret.c_str(), secret.size()))); + D2TsigKey(Name("wrong.com"), + TSIGKey::HMACMD5_NAME(), + secret.c_str(), secret.size()))); // Build a request message @@ -658,9 +658,9 @@ TEST_F(D2UpdateMessageTest, allValidTSIG) { dns::Name key_name("test_key"); std::string secret("random text for secret"); for (int i = 0; i < algorithms.size(); ++i) { - dns::TSIGKey key(key_name, - TSIGKeyInfo::stringToAlgorithmName(algorithms[i]), - secret.c_str(), secret.size()); + D2TsigKey key(key_name, + TSIGKeyInfo::stringToAlgorithmName(algorithms[i]), + secret.c_str(), secret.size()); // Build a request message D2UpdateMessage msg; diff --git a/src/bin/d2/tests/dns_client_unittests.cc b/src/bin/d2/tests/dns_client_unittests.cc index a795f0db2e79411cc6249d3f28baffba89250735..85927cbe01762b4e248aee300636dd41ab0c3dee 100644 --- a/src/bin/d2/tests/dns_client_unittests.cc +++ b/src/bin/d2/tests/dns_client_unittests.cc @@ -205,8 +205,8 @@ public: // signing with the wrong key. void TSIGReceiveHandler(udp::socket* socket, udp::endpoint* remote, size_t receive_length, - TSIGKeyPtr client_key, - TSIGKeyPtr server_key) { + D2TsigKeyPtr client_key, + D2TsigKeyPtr server_key) { TSIGContextPtr context; if (client_key) { @@ -413,7 +413,7 @@ public: // @param server_key TSIG key the "server" should use to sign the response. // If this is NULL, then client_key is used. // @param should_pass indicates if the test should pass. - void runTSIGTest(TSIGKeyPtr client_key, TSIGKeyPtr server_key, + void runTSIGTest(D2TsigKeyPtr client_key, D2TsigKeyPtr server_key, bool should_pass = true) { // Tell operator() method if we expect an invalid response. corrupt_response_ = !should_pass; @@ -485,18 +485,18 @@ TEST_F(DNSClientTest, invalidTimeout) { // Verifies that TSIG can be used to sign requests and verify responses. TEST_F(DNSClientTest, runTSIGTest) { std::string secret ("key number one"); - TSIGKeyPtr key_one; + D2TsigKeyPtr key_one; ASSERT_NO_THROW(key_one.reset(new - TSIGKey(Name("one.com"), - TSIGKey::HMACMD5_NAME(), - secret.c_str(), secret.size()))); + D2TsigKey(Name("one.com"), + TSIGKey::HMACMD5_NAME(), + secret.c_str(), secret.size()))); secret = "key number two"; - TSIGKeyPtr key_two; + D2TsigKeyPtr key_two; ASSERT_NO_THROW(key_two.reset(new - TSIGKey(Name("two.com"), - TSIGKey::HMACMD5_NAME(), - secret.c_str(), secret.size()))); - TSIGKeyPtr nokey; + D2TsigKey(Name("two.com"), + TSIGKey::HMACMD5_NAME(), + secret.c_str(), secret.size()))); + D2TsigKeyPtr nokey; // Should be able to send and receive with no keys. // Neither client nor server will attempt to sign or verify. diff --git a/src/bin/d2/tests/nc_test_utils.cc b/src/bin/d2/tests/nc_test_utils.cc index f4888d492a336457fd0533a0a92d49acc5fa4905..358387bdc7821742c76292891a77d06e944c8d29 100644 --- a/src/bin/d2/tests/nc_test_utils.cc +++ b/src/bin/d2/tests/nc_test_utils.cc @@ -173,11 +173,11 @@ FauxServer::requestHandler(const boost::system::error_code& error, if (response_mode == INVALID_TSIG) { // Create a different key to sign the response. std::string secret ("key that doesn't match"); - dns::TSIGKeyPtr key; + D2TsigKeyPtr key; ASSERT_NO_THROW(key.reset(new - dns::TSIGKey(dns::Name("badkey"), - dns::TSIGKey::HMACMD5_NAME(), - secret.c_str(), secret.size()))); + D2TsigKey(dns::Name("badkey"), + dns::TSIGKey::HMACMD5_NAME(), + secret.c_str(), secret.size()))); context.reset(new dns::TSIGContext(*key)); } diff --git a/src/bin/d2/tests/nc_test_utils.h b/src/bin/d2/tests/nc_test_utils.h index 543004b627c9df82d38269e7074fbff081f2fd62..4cfff4cb92cacaa6f09d0784deb25292dde071e8 100644 --- a/src/bin/d2/tests/nc_test_utils.h +++ b/src/bin/d2/tests/nc_test_utils.h @@ -61,7 +61,7 @@ public: bool perpetual_receive_; // TSIG Key to use to verify requests and sign responses. If its // NULL TSIG is not used. - dns::TSIGKeyPtr tsig_key_; + D2TsigKeyPtr tsig_key_; /// @brief Constructor /// @@ -117,7 +117,7 @@ public: /// /// @param tsig_key Pointer to the TSIG key to use. If the pointer is /// empty, TSIG will not be used. - void setTSIGKey (const dns::TSIGKeyPtr& tsig_key) { + void setTSIGKey(const D2TsigKeyPtr& tsig_key) { tsig_key_ = tsig_key; } }; diff --git a/src/bin/d2/tests/testdata/d2_cfg_tests.json b/src/bin/d2/tests/testdata/d2_cfg_tests.json index 7780e7913e2bfc6bf1ca281246a9446396a0e0b8..6cb087fa0ace206721b94d487f489acece4f562c 100644 --- a/src/bin/d2/tests/testdata/d2_cfg_tests.json +++ b/src/bin/d2/tests/testdata/d2_cfg_tests.json @@ -702,7 +702,7 @@ #----- ,{ "description" : "D2.tsig-keys, invalid secret", -"logic-error" : "Cannot make TSIGKey: Incomplete input for base64: bogus (:1:62)", +"logic-error" : "Cannot make D2TsigKey: Incomplete input for base64: bogus (:1:62)", "data" : { "forward-ddns" : {}, diff --git a/src/lib/d2srv/Makefile.am b/src/lib/d2srv/Makefile.am index 78de1a20a29b73ccafc1d4ae1fdb3dd874d85e27..aad64e6c3328f5b99efd8cb2ac498c30dc407a58 100644 --- a/src/lib/d2srv/Makefile.am +++ b/src/lib/d2srv/Makefile.am @@ -16,6 +16,8 @@ libkea_d2srv_la_SOURCES += d2_config.cc d2_config.h libkea_d2srv_la_SOURCES += d2_log.cc d2_log.h libkea_d2srv_la_SOURCES += d2_messages.cc d2_messages.h libkea_d2srv_la_SOURCES += d2_simple_parser.cc d2_simple_parser.h +libkea_d2srv_la_SOURCES += d2_stats.cc d2_stats.h +libkea_d2srv_la_SOURCES += d2_tsig_key.cc d2_tsig_key.h EXTRA_DIST += d2_messages.mes libkea_d2srv_la_CXXFLAGS = $(AM_CXXFLAGS) @@ -25,6 +27,7 @@ libkea_d2srv_la_LIBADD = libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/cfgrpt/libcfgrpt.la libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la diff --git a/src/lib/d2srv/d2_config.cc b/src/lib/d2srv/d2_config.cc index 40baf5f60974c80baa73b9498742dd1d65ad9fa5..21c7bf4a5d4116026e197e3e31fa75b6845caaef 100644 --- a/src/lib/d2srv/d2_config.cc +++ b/src/lib/d2srv/d2_config.cc @@ -165,7 +165,7 @@ void TSIGKeyInfo::remakeKey() { try { // Since our secret value is base64 encoded already, we need to - // build the input string for the appropriate TSIGKey constructor. + // build the input string for the appropriate D2TsigKey constructor. // If secret isn't a valid base64 value, the constructor will throw. std::ostringstream stream; stream << dns::Name(name_).toText() << ":" @@ -175,9 +175,9 @@ TSIGKeyInfo::remakeKey() { stream << ":" << digestbits_; } - tsig_key_.reset(new dns::TSIGKey(stream.str())); + tsig_key_.reset(new D2TsigKey(stream.str())); } catch (const std::exception& ex) { - isc_throw(D2CfgError, "Cannot make TSIGKey: " << ex.what()); + isc_throw(D2CfgError, "Cannot make D2TsigKey: " << ex.what()); } } @@ -439,7 +439,7 @@ TSIGKeyInfoParser::parse(ConstElementPtr key_config) { } // Everything should be valid, so create the key instance. - // It is possible for the asiodns::dns::TSIGKey create to fail such as + // It is possible for the D2TsigKey constructor to fail such as // with an invalid secret content. TSIGKeyInfoPtr key_info; try { diff --git a/src/lib/d2srv/d2_config.h b/src/lib/d2srv/d2_config.h index 892cd9729bcf39c6c66b6724061fcba520c3e382..6162ec5ea15154ed008af09adc9ad2af9e1b0772 100644 --- a/src/lib/d2srv/d2_config.h +++ b/src/lib/d2srv/d2_config.h @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -343,8 +343,8 @@ public: /// @brief Getter which returns the TSIG key used to sign and verify /// messages /// - /// @return const pointer reference to dns::TSIGKey. - const dns::TSIGKeyPtr& getTSIGKey() const { + /// @return const pointer reference to @c D2TsigKeyPtr + const D2TsigKeyPtr& getTSIGKey() const { return (tsig_key_); } @@ -397,7 +397,7 @@ private: uint32_t digestbits_; /// @brief The actual TSIG key. - dns::TSIGKeyPtr tsig_key_; + D2TsigKeyPtr tsig_key_; }; /// @brief Defines a pointer for TSIGKeyInfo instances. diff --git a/src/lib/d2srv/d2_stats.cc b/src/lib/d2srv/d2_stats.cc new file mode 100644 index 0000000000000000000000000000000000000000..5c94f4304ffa8e363900676458d3d0e5e16f93b5 --- /dev/null +++ b/src/lib/d2srv/d2_stats.cc @@ -0,0 +1,44 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// Defines the logger used by the top-level component of kea-dhcp-ddns. + +#include + +#include + +using namespace std; + +namespace isc { +namespace d2 { + +set +D2Stats::ncr = { + "ncr-received", + "ncr-invalid", + "ncr-error" +}; + +set +D2Stats::update = { + "update-sent", + "update-signed", + "update-unsigned", + "update-success", + "update-timeout", + "update-error" +}; + +set +D2Stats::key = { + "update-sent", + "update-success", + "update-timeout", + "update-error" +}; + +} // namespace d2 +} // namespace isc diff --git a/src/lib/d2srv/d2_stats.h b/src/lib/d2srv/d2_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..be40415e50de11fbbdede698009be97717020af3 --- /dev/null +++ b/src/lib/d2srv/d2_stats.h @@ -0,0 +1,48 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef D2_STATS_H +#define D2_STATS_H + +#include +#include + +namespace isc { +namespace d2 { + +/// @brief Statistics Names. +class D2Stats { +public: + /// @brief Global NCR statistics names. + /// + /// - ncr-received + /// - ncr-invalid + /// - ncr-error + static std::set ncr; + + /// @brief Global DNS update statistics names. + /// + /// - update-sent + /// - update-signed + /// - update-unsigned + /// - update-success + /// - update-timeout + /// - update-error + static std::set update; + + /// @brief Key DNS update statistics names. + /// + /// - update-sent + /// - update-success + /// - update-timeout + /// - update-error + static std::set key; +}; + +} // namespace d2 +} // namespace isc + +#endif // D2_STATS_H diff --git a/src/lib/d2srv/d2_tsig_key.cc b/src/lib/d2srv/d2_tsig_key.cc new file mode 100644 index 0000000000000000000000000000000000000000..2d9055a833834c694955b87135c99cd4ea178ee9 --- /dev/null +++ b/src/lib/d2srv/d2_tsig_key.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// Defines the logger used by the top-level component of kea-dhcp-ddns. + +#include + +#include +#include +#include + +using namespace isc::dns; +using namespace isc::stats; +using namespace std; + +namespace isc { +namespace d2 { + +D2TsigKey::D2TsigKey(const std::string& key_spec) : TSIGKey(key_spec) { + initStats(); +} + +D2TsigKey::D2TsigKey(const Name& key_name, const Name& algorithm_name, + const void* secret, size_t secret_len, size_t digestbits) + : TSIGKey(key_name, algorithm_name, secret, secret_len, digestbits) { + initStats(); +} + +void +D2TsigKey::initStats() { + StatsMgr& stats_mgr = StatsMgr::instance(); + const string& kname = getKeyName().toText(); + for (const auto& name : D2Stats::key) { + const string& sname = StatsMgr::generateName("key", kname, name); + stats_mgr.setValue(sname, static_cast(0)); + } +} + +D2TsigKey::~D2TsigKey() { + StatsMgr& stats_mgr = StatsMgr::instance(); + const string& kname = getKeyName().toText(); + for (const auto& name : D2Stats::key) { + string sname = StatsMgr::generateName("key", kname, name); + stats_mgr.del(sname); + } +} + +void +D2TsigKey::resetStats() { + StatsMgr& stats_mgr = StatsMgr::instance(); + const string& kname = getKeyName().toText(); + for (const auto& name : D2Stats::key) { + string sname = StatsMgr::generateName("key", kname, name); + stats_mgr.reset(sname); + } +} + +} // namespace d2 +} // namespace isc diff --git a/src/lib/d2srv/d2_tsig_key.h b/src/lib/d2srv/d2_tsig_key.h new file mode 100644 index 0000000000000000000000000000000000000000..2815cb0a7957e3766aae4dad645ec238643aa908 --- /dev/null +++ b/src/lib/d2srv/d2_tsig_key.h @@ -0,0 +1,66 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef D2_TSIG_KEY_H +#define D2_TSIG_KEY_H + +#include +#include +#include + +namespace isc { +namespace d2 { + +/// @brief Statistics keeping extension of the DNS TSIGKey class. +/// +/// Implements a TSIGKey derived class which can be used as the value +/// of TSIGKeyPtr so with minimal or no update to the DNS++ library. +class D2TsigKey : public dns::TSIGKey { +public: + /// @brief Constructor. + /// + /// Initialize the key statistics. + /// + /// @param key_spec Specification of the key + /// (name:secret[:algorithm][:digestbits]) + explicit D2TsigKey(const std::string& key_spec); + + /// @brief Constructor. + /// + /// Initialize the key statistics. + /// + /// @param key_name The name of the key as a domain name. + /// @param algorithm_name The hash algorithm used for this key in the + /// form of domain name. + /// @param secret Point to a binary sequence of the shared secret to be + /// used for this key. + /// @param secret_len The size of the binary %data (@c secret) in bytes. + /// @param digestbits The number of bits to include in the digest + /// (0 means to include all) + D2TsigKey(const dns::Name& key_name, const dns::Name& algorithm_name, + const void* secret, size_t secret_len, size_t digestbits = 0); + + /// @brief Destructor. + /// + /// Remove the key statistics. + virtual ~D2TsigKey(); + + /// @brief Reset statistics. + /// + virtual void resetStats(); + +private: + /// @brief Initialize key statistics. + void initStats(); +}; + +/// @brief Type of pointer to a D2 TSIG key. +typedef boost::shared_ptr D2TsigKeyPtr; + +} // namespace d2 +} // namespace isc + +#endif // D2_TSIG_KEY_H diff --git a/src/lib/d2srv/tests/Makefile.am b/src/lib/d2srv/tests/Makefile.am index fb7c76003db6b01116ba7fc7ea36d97024ea2838..caede036f9ecb048c501cb163ffcb711b33d15c1 100644 --- a/src/lib/d2srv/tests/Makefile.am +++ b/src/lib/d2srv/tests/Makefile.am @@ -19,7 +19,7 @@ if HAVE_GTEST TESTS += libd2srv_unittests libd2srv_unittests_SOURCES = run_unittests.cc -# Currently no unit test file was moved even partially. +libd2srv_unittests_SOURCES += d2_tsig_key_unittest.cc libd2srv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) libd2srv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) @@ -27,6 +27,7 @@ libd2srv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) libd2srv_unittests_LDADD = $(top_builddir)/src/lib/d2srv/libkea-d2srv.la libd2srv_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la libd2srv_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libd2srv_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la libd2srv_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la libd2srv_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la libd2srv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la diff --git a/src/lib/d2srv/tests/d2_tsig_key_unittest.cc b/src/lib/d2srv/tests/d2_tsig_key_unittest.cc new file mode 100644 index 0000000000000000000000000000000000000000..9456ef12716effd42853dd8b51e5c9c614701a88 --- /dev/null +++ b/src/lib/d2srv/tests/d2_tsig_key_unittest.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +using namespace isc::d2; +using namespace isc::data; +using namespace isc::stats; +using namespace std; + +namespace { + +/// @brief Check statistics names. +TEST(D2StatsTest, names) { + ASSERT_EQ(3, D2Stats::ncr.size()); + ASSERT_EQ(6, D2Stats::update.size()); + ASSERT_EQ(4, D2Stats::key.size()); +} + +/// @brief Fixture class for TSIG key / DNS update statistics. +class D2TsigKeyTest : public ::testing::Test { +public: + /// @brief Constructor. + D2TsigKeyTest() { + StatsMgr::instance(); + StatsMgr::instance().removeAll(); + StatsMgr::instance().setMaxSampleCountDefault(0); + } + + /// @brief Destructor. + ~D2TsigKeyTest() { + StatsMgr::instance().removeAll(); + StatsMgr::instance().setMaxSampleCountDefault(0); + } +}; + +/// @brief Check TSIG key life. +TEST_F(D2TsigKeyTest, key) { + // Get the statistics manager. + StatsMgr& stat_mgr = StatsMgr::instance(); + ASSERT_EQ(0, stat_mgr.count()); + + // Create a key. + const string& key_spec = "foo.bar.::test"; + D2TsigKeyPtr key(new D2TsigKey(key_spec)); + EXPECT_EQ(4, stat_mgr.count()); + + // Get the 'sent' statistics. + const string& stat_name = "key[foo.bar.].update-sent"; + EXPECT_EQ(1, stat_mgr.getSize(stat_name)); + ObservationPtr stat = stat_mgr.getObservation(stat_name); + ASSERT_TRUE(stat); + IntegerSample sample; + ASSERT_NO_THROW(sample = stat->getInteger()); + EXPECT_EQ(0, sample.first); + + // Increment the 'sent' statistics. + stat_mgr.addValue(stat_name, static_cast(1)); + stat = stat_mgr.getObservation(stat_name); + ASSERT_TRUE(stat); + ASSERT_NO_THROW(sample = stat->getInteger()); + EXPECT_EQ(1, sample.first); + + // Reset the key statistics. + ASSERT_NO_THROW(key->resetStats()); + stat = stat_mgr.getObservation(stat_name); + ASSERT_TRUE(stat); + ASSERT_NO_THROW(sample = stat->getInteger()); + EXPECT_EQ(0, sample.first); + + // Destroy the key: its stats are removed. + key.reset(); + EXPECT_EQ(0, stat_mgr.count()); + stat = stat_mgr.getObservation(stat_name); + EXPECT_FALSE(stat); +} + +} // end of anonymous namespace diff --git a/src/lib/dhcp_ddns/Makefile.am b/src/lib/dhcp_ddns/Makefile.am index 4769f616bbff4811ede6e134b24165ab8e32c98f..e50c85c2712d2a0053e6ffe4b0940888f5743dd5 100644 --- a/src/lib/dhcp_ddns/Makefile.am +++ b/src/lib/dhcp_ddns/Makefile.am @@ -24,6 +24,7 @@ libkea_dhcp_ddns_la_LDFLAGS += $(CRYPTO_LDFLAGS) libkea_dhcp_ddns_la_LDFLAGS += -no-undefined -version-info 16:0:0 libkea_dhcp_ddns_la_LIBADD = +libkea_dhcp_ddns_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la libkea_dhcp_ddns_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la libkea_dhcp_ddns_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libkea_dhcp_ddns_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la diff --git a/src/lib/dhcp_ddns/ncr_udp.cc b/src/lib/dhcp_ddns/ncr_udp.cc index 9ba44ca71308aa1f3e11c8b564487e01e67f27ea..fc46f5b651b8dacde2c5136e1b77ae3ff24d5943 100644 --- a/src/lib/dhcp_ddns/ncr_udp.cc +++ b/src/lib/dhcp_ddns/ncr_udp.cc @@ -8,6 +8,7 @@ #include #include +#include #include @@ -161,9 +162,13 @@ NameChangeUDPListener::receiveCompletionHandler(const bool successful, try { ncr = NameChangeRequest::fromFormat(format_, input_buffer); + isc::stats::StatsMgr::instance().addValue("ncr-received", + static_cast(0)); } catch (const NcrMessageError& ex) { // log it and go back to listening LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_INVALID_NCR).arg(ex.what()); + isc::stats::StatsMgr::instance().addValue("ncr-invalid", + static_cast(0)); // Queue up the next receive. // NOTE: We must call the base class, NEVER doReceive @@ -181,6 +186,8 @@ NameChangeUDPListener::receiveCompletionHandler(const bool successful, } else { LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_NCR_UDP_RECV_ERROR) .arg(error_code.message()); + isc::stats::StatsMgr::instance().addValue("ncr-error", + static_cast(0)); result = ERROR; } } @@ -376,5 +383,5 @@ NameChangeUDPSender::closeWatchSocket() { } } -}; // end of isc::dhcp_ddns namespace -}; // end of isc namespace +} // end of isc::dhcp_ddns namespace +} // end of isc namespace diff --git a/src/lib/dhcp_ddns/tests/Makefile.am b/src/lib/dhcp_ddns/tests/Makefile.am index 1bbeb8053a942b528ca5eda7619def47733f97ec..e1f27d1fa24d2aa201ba6685ad355a1f81b48486 100644 --- a/src/lib/dhcp_ddns/tests/Makefile.am +++ b/src/lib/dhcp_ddns/tests/Makefile.am @@ -32,6 +32,7 @@ libdhcp_ddns_unittests_CXXFLAGS = $(AM_CXXFLAGS) libdhcp_ddns_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) libdhcp_ddns_unittests_LDADD = $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la +libdhcp_ddns_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la libdhcp_ddns_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la libdhcp_ddns_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libdhcp_ddns_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la