From: Francis Dupont Date: Mon, 5 Jun 2023 15:15:59 +0000 (+0200) Subject: [#2707] Checkpoint X-Git-Tag: Kea-2.4.0~138 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1121e02192fa9a54586b8007cebcf3f5228041f6;p=thirdparty%2Fkea.git [#2707] Checkpoint --- diff --git a/doc/sphinx/api-files.txt b/doc/sphinx/api-files.txt index b4b602e3b4..6d63c15aa9 100644 --- a/doc/sphinx/api-files.txt +++ b/doc/sphinx/api-files.txt @@ -15,6 +15,7 @@ src/share/api/class-list.json src/share/api/class-update.json src/share/api/config-backend-pull.json src/share/api/config-get.json +src/share/api/config-hash-get.json src/share/api/config-reload.json src/share/api/config-set.json src/share/api/config-test.json diff --git a/doc/sphinx/arm/ctrl-channel.rst b/doc/sphinx/arm/ctrl-channel.rst index 4ede42c02d..017fe6bf19 100644 --- a/doc/sphinx/arm/ctrl-channel.rst +++ b/doc/sphinx/arm/ctrl-channel.rst @@ -369,6 +369,35 @@ An example command invocation looks like this: "command": "config-get" } +.. isccmd:: config-hash-get +.. _command-config-hash-get: + +The ``config-hash-get`` Command +------------------------------- + +The ``config-hash-get`` command retrieves the SHA-256 hash of the current +configuration used by the server. This command does not take any parameters. +The returned hash can be used to detect configuration changes. + +An example command invocation looks like this: + +:: + + { + "command": "config-hash-get" + } + +And the server's response: + +:: + + { + "result": 0, + "arguments": { + "hash": "5C3C90EF7035249E2FF74D003C19F34EE0B83A3D329E741B52B2EF95A2C9CC5C" + } + } + .. isccmd:: config-reload .. _command-config-reload: @@ -816,6 +845,8 @@ The D2 server supports only a subset of the DHCPv4/DHCPv6 server commands: - :isccmd:`config-get` +- :isccmd:`config-hash-get` + - :isccmd:`config-reload` - :isccmd:`config-set` @@ -845,6 +876,8 @@ commands are handled by the CA and they relate to the CA process itself: - :isccmd:`config-get` +- :isccmd:`config-hash-get` + - :isccmd:`config-reload` - :isccmd:`config-set` diff --git a/doc/sphinx/arm/ddns.rst b/doc/sphinx/arm/ddns.rst index 66d436289f..b559255070 100644 --- a/doc/sphinx/arm/ddns.rst +++ b/doc/sphinx/arm/ddns.rst @@ -304,6 +304,7 @@ The D2 server supports the following operational commands: - :isccmd:`build-report` - :isccmd:`config-get` +- :isccmd:`config-hash-get` - :isccmd:`config-reload` - :isccmd:`config-set` - :isccmd:`config-test` diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst index fb80e1d64b..acb915a130 100644 --- a/doc/sphinx/arm/dhcp4-srv.rst +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -7336,6 +7336,7 @@ The DHCPv4 server supports the following operational commands: - :isccmd:`build-report` - :isccmd:`config-get` +- :isccmd:`config-hash-get` - :isccmd:`config-reload` - :isccmd:`config-set` - :isccmd:`config-test` diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst index 1af7b60297..6c1ed6a726 100644 --- a/doc/sphinx/arm/dhcp6-srv.rst +++ b/doc/sphinx/arm/dhcp6-srv.rst @@ -5002,7 +5002,7 @@ file and in the host database backend, via :ischooklib:`libdhcp_host_cmds.so`. Setting ``ip-reservations-unique`` to ``false`` when using memfile, MySQL or PostgreSQL is supported. This setting is not supported when using Host Cache (see :ref:`hooks-host-cache`), and the RADIUS backend -(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the +(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the same IP. If either of these hooks are loaded and ``ip-reservations-unique`` is set to ``false``, then a configuration error will be emitted and the server will fail to start. @@ -7137,6 +7137,7 @@ The DHCPv6 server supports the following operational commands: - :isccmd:`build-report` - :isccmd:`config-get` +- :isccmd:`config-hash-get` - :isccmd:`config-reload` - :isccmd:`config-set` - :isccmd:`config-test` diff --git a/src/bin/agent/ca_controller.cc b/src/bin/agent/ca_controller.cc index 7c4a518aaf..bc71073578 100644 --- a/src/bin/agent/ca_controller.cc +++ b/src/bin/agent/ca_controller.cc @@ -59,6 +59,9 @@ CtrlAgentController::registerCommands() { CtrlAgentCommandMgr::instance().registerCommand(CONFIG_GET_COMMAND, std::bind(&DControllerBase::configGetHandler, this, ph::_1, ph::_2)); + CtrlAgentCommandMgr::instance().registerCommand(CONFIG_HASH_GET_COMMAND, + std::bind(&DControllerBase::configHashGetHandler, this, ph::_1, ph::_2)); + CtrlAgentCommandMgr::instance().registerCommand(CONFIG_RELOAD_COMMAND, std::bind(&DControllerBase::configReloadHandler, this, ph::_1, ph::_2)); @@ -85,6 +88,7 @@ void CtrlAgentController::deregisterCommands() { CtrlAgentCommandMgr::instance().deregisterCommand(BUILD_REPORT_COMMAND); CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_GET_COMMAND); + CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_HASH_GET_COMMAND); CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_RELOAD_COMMAND); CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_SET_COMMAND); CtrlAgentCommandMgr::instance().deregisterCommand(CONFIG_TEST_COMMAND); diff --git a/src/bin/d2/d2_controller.cc b/src/bin/d2/d2_controller.cc index c9799d3c2c..0d0d816791 100644 --- a/src/bin/d2/d2_controller.cc +++ b/src/bin/d2/d2_controller.cc @@ -62,6 +62,9 @@ D2Controller::registerCommands() { CommandMgr::instance().registerCommand(CONFIG_GET_COMMAND, std::bind(&D2Controller::configGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand(CONFIG_HASH_GET_COMMAND, + std::bind(&D2Controller::configHashGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand(CONFIG_RELOAD_COMMAND, std::bind(&D2Controller::configReloadHandler, this, ph::_1, ph::_2)); @@ -106,6 +109,7 @@ D2Controller::deregisterCommands() { // Deregister any registered commands (please keep in alphabetic order) CommandMgr::instance().deregisterCommand(BUILD_REPORT_COMMAND); CommandMgr::instance().deregisterCommand(CONFIG_GET_COMMAND); + CommandMgr::instance().deregisterCommand(CONFIG_HASH_GET_COMMAND); CommandMgr::instance().deregisterCommand(CONFIG_RELOAD_COMMAND); CommandMgr::instance().deregisterCommand(CONFIG_SET_COMMAND); CommandMgr::instance().deregisterCommand(CONFIG_TEST_COMMAND); diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 8dfac250d9..03917c50a9 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -289,6 +291,27 @@ ControlledDhcpv4Srv::commandConfigGetHandler(const string&, return (createAnswer(CONTROL_RESULT_SUCCESS, config)); } +ConstElementPtr +ControlledDhcpv4Srv::commandConfigHashGetHandler(const string&, + ConstElementPtr /*args*/) { + ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement(); + // Assume that config is never null. + string config_txt = config->str(); + OutputBuffer hash_data(0); + isc::cryptolink::digest(config_txt.c_str(), + config_txt.size(), + isc::cryptolink::HashAlgorithm::SHA256, + hash_data); + vector hash; + hash.resize(hash_data.getLength()); + if (hash.size() > 0) { + memmove(&hash[0], hash_data.getData(), hash.size()); + } + ElementPtr params = Element::createMap(); + params->set("hash", Element::create(encode::encodeHex(hash))); + return (createAnswer(CONTROL_RESULT_SUCCESS, params)); +} + ConstElementPtr ControlledDhcpv4Srv::commandConfigWriteHandler(const string&, ConstElementPtr args) { @@ -839,6 +862,9 @@ ControlledDhcpv4Srv::processCommand(const string& command, } else if (command == "config-get") { return (srv->commandConfigGetHandler(command, args)); + } else if (command == "config-hash-get") { + return (srv->commandConfigHashGetHandler(command, args)); + } else if (command == "config-test") { return (srv->commandConfigTestHandler(command, args)); @@ -1145,6 +1171,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P CommandMgr::instance().registerCommand("config-get", std::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand("config-hash-get", + std::bind(&ControlledDhcpv4Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand("config-reload", std::bind(&ControlledDhcpv4Srv::commandConfigReloadHandler, this, ph::_1, ph::_2)); @@ -1241,6 +1270,7 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() { CommandMgr::instance().deregisterCommand("build-report"); CommandMgr::instance().deregisterCommand("config-backend-pull"); CommandMgr::instance().deregisterCommand("config-get"); + CommandMgr::instance().deregisterCommand("config-hash-get"); CommandMgr::instance().deregisterCommand("config-reload"); CommandMgr::instance().deregisterCommand("config-set"); CommandMgr::instance().deregisterCommand("config-test"); diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index 564399cba7..b18f9dd914 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -193,9 +193,9 @@ private: commandConfigReloadHandler(const std::string& command, isc::data::ConstElementPtr args); - /// @brief handler for processing 'get-config' command + /// @brief handler for processing 'config-get' command /// - /// This handler processes get-config command, which retrieves + /// This handler processes config-get command, which retrieves /// the current configuration and returns it in response. /// /// @param command (ignored) @@ -205,9 +205,21 @@ private: commandConfigGetHandler(const std::string& command, isc::data::ConstElementPtr args); - /// @brief handler for processing 'write-config' command + /// @brief handler for processing 'config-hash-get' command /// - /// This handle processes write-config command, which writes the + /// This handler processes config-hash-get command, which retrieves + /// the hash of the current configuration and returns it in response. + /// + /// @param command (ignored) + /// @param args (ignored) + /// @return hash of current configuration wrapped in a response + isc::data::ConstElementPtr + commandConfigHashGetHandler(const std::string& command, + isc::data::ConstElementPtr args); + + /// @brief handler for processing 'config-write' command + /// + /// This handle processes config-write command, which writes the /// current configuration to disk. This command takes one optional /// parameter called filename. If specified, the current configuration /// will be written to that file. If not specified, the file used during diff --git a/src/lib/process/d_controller.cc b/src/lib/process/d_controller.cc index 5c11525227..077e08c0d3 100644 --- a/src/lib/process/d_controller.cc +++ b/src/lib/process/d_controller.cc @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -22,9 +24,10 @@ #include using namespace isc::asiolink; -using namespace isc::data; using namespace isc::config; +using namespace isc::data; using namespace isc::hooks; +using namespace isc::util; namespace ph = std::placeholders; namespace isc { @@ -448,8 +451,21 @@ ConstElementPtr DControllerBase::configGetHandler(const std::string&, ConstElementPtr /*args*/) { ConstElementPtr config = process_->getCfgMgr()->getContext()->toElement(); - - return (createAnswer(CONTROL_RESULT_SUCCESS, config)); + // Assume that config is never null. + std::string config_txt = config->str(); + OutputBuffer hash_data(0); + isc::cryptolink::digest(config_txt.c_str(), + config_txt.size(), + isc::cryptolink::HashAlgorithm::SHA256, + hash_data); + std::vector hash; + hash.resize(hash_data.getLength()); + if (hash.size() > 0) { + memmove(&hash[0], hash_data.getData(), hash.size()); + } + ElementPtr params = Element::createMap(); + params->set("hash", Element::create(encode::encodeHex(hash))); + return (createAnswer(CONTROL_RESULT_SUCCESS, params)); } ConstElementPtr diff --git a/src/lib/process/d_controller.h b/src/lib/process/d_controller.h index 53c4abb75e..e16253e372 100644 --- a/src/lib/process/d_controller.h +++ b/src/lib/process/d_controller.h @@ -265,6 +265,18 @@ public: configGetHandler(const std::string& command, isc::data::ConstElementPtr args); + /// @brief handler for config-hash-get command + /// + /// This method handles the config-hash-get command, which retrieves + /// the current configuration and returns it in response. + /// + /// @param command (ignored) + /// @param args (ignored) + /// @return hash of current configuration wrapped in a response + isc::data::ConstElementPtr + configHashGetHandler(const std::string& command, + isc::data::ConstElementPtr args); + /// @brief handler for config-write command /// /// This handle processes write-config command, which writes the diff --git a/src/lib/process/d_process.h b/src/lib/process/d_process.h index 472e708f6f..e2b9309695 100644 --- a/src/lib/process/d_process.h +++ b/src/lib/process/d_process.h @@ -36,6 +36,9 @@ static const std::string BUILD_REPORT_COMMAND("build-report"); /// @brief String value for the config-get command. static const std::string CONFIG_GET_COMMAND("config-get"); +/// @brief String value for the config-hash-get command. +static const std::string CONFIG_HASH_GET_COMMAND("config-hash-get"); + /// @brief String value for the config-write command. static const std::string CONFIG_WRITE_COMMAND("config-write"); diff --git a/src/share/api/api_files.mk b/src/share/api/api_files.mk index f10286bdb0..a9ff829f8c 100644 --- a/src/share/api/api_files.mk +++ b/src/share/api/api_files.mk @@ -15,6 +15,7 @@ api_files += $(top_srcdir)/src/share/api/class-list.json api_files += $(top_srcdir)/src/share/api/class-update.json api_files += $(top_srcdir)/src/share/api/config-backend-pull.json api_files += $(top_srcdir)/src/share/api/config-get.json +api_files += $(top_srcdir)/src/share/api/config-hash-get.json api_files += $(top_srcdir)/src/share/api/config-reload.json api_files += $(top_srcdir)/src/share/api/config-set.json api_files += $(top_srcdir)/src/share/api/config-test.json diff --git a/src/share/api/config-hash-get.json b/src/share/api/config-hash-get.json new file mode 100644 index 0000000000..d85abd1ada --- /dev/null +++ b/src/share/api/config-hash-get.json @@ -0,0 +1,30 @@ +{ + "access": "read", + "avail": "2.4.0", + "brief": [ + "This command retrieves the hash of the current configuration used by the server. The configuration is essentially the same as the contents of the configuration file, but includes additional changes made by other commands and due to parameters' inheritance." + ], + "cmd-comment": [ + "This command takes no parameters." + ], + "cmd-syntax": [ + "{", + " \"command\": \"config-hash-get\"", + "}" + ], + "name": "config-hash-get", + "resp-syntax": [ + "{", + " \"result\": ,", + " \"arguments\": {", + " \"hash\": ", + " }", + "}" + ], + "support": [ + "kea-dhcp4", + "kea-dhcp6", + "kea-dhcp-ddns", + "kea-ctrl-agent" + ] +}