From: Francis Dupont Date: Mon, 5 Jun 2023 16:13:22 +0000 (+0200) Subject: [#2707] Added config-hash-get with SHA-256 X-Git-Tag: Kea-2.4.0~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3026461a4a2e2d7678d9de0ba6813a2b6f76ae0;p=thirdparty%2Fkea.git [#2707] Added config-hash-get with SHA-256 --- diff --git a/src/bin/agent/tests/ca_controller_unittests.cc b/src/bin/agent/tests/ca_controller_unittests.cc index f0f8848027..2513d2dc61 100644 --- a/src/bin/agent/tests/ca_controller_unittests.cc +++ b/src/bin/agent/tests/ca_controller_unittests.cc @@ -480,6 +480,7 @@ TEST_F(CtrlAgentControllerTest, registeredCommands) { // Check that the following command are really available. checkCommandRegistered("build-report"); checkCommandRegistered("config-get"); + checkCommandRegistered("config-hash-get"); checkCommandRegistered("config-reload"); checkCommandRegistered("config-set"); checkCommandRegistered("config-test"); diff --git a/src/bin/d2/tests/d2_command_unittest.cc b/src/bin/d2/tests/d2_command_unittest.cc index c92cbc3518..564b5cd4e9 100644 --- a/src/bin/d2/tests/d2_command_unittest.cc +++ b/src/bin/d2/tests/d2_command_unittest.cc @@ -534,6 +534,7 @@ TEST_F(CtrlChannelD2Test, commandsRegistration) { EXPECT_TRUE(command_list.find("\"list-commands\"") != string::npos); EXPECT_TRUE(command_list.find("\"build-report\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"config-hash-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-reload\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-set\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-test\"") != string::npos); @@ -627,6 +628,7 @@ TEST_F(CtrlChannelD2Test, listCommands) { // We expect the server to report at least the following commands: checkListCommands(rsp, "build-report"); checkListCommands(rsp, "config-get"); + checkListCommands(rsp, "config-hash-get"); checkListCommands(rsp, "config-reload"); checkListCommands(rsp, "config-set"); checkListCommands(rsp, "config-test"); @@ -704,6 +706,33 @@ TEST_F(CtrlChannelD2Test, configGet) { EXPECT_TRUE(cfg->get("DhcpDdns")); } +// Tests if the server returns the hash of its configuration using +// config-hash-get. +TEST_F(CtrlChannelD2Test, configHashGet) { + EXPECT_NO_THROW(createUnixChannelServer()); + string response; + + sendUnixCommand("{ \"command\": \"config-hash-get\" }", response); + ConstElementPtr rsp; + + // The response should be a valid JSON. + EXPECT_NO_THROW(rsp = Element::fromJSON(response)); + ASSERT_TRUE(rsp); + + int status; + ConstElementPtr args = parseAnswer(status, rsp); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status); + + // Ok, now roughly check if the response seems legit. + ASSERT_TRUE(args); + ASSERT_EQ(Element::map, args->getType()); + ConstElementPtr hash = args->get("hash"); + ASSERT_TRUE(hash); + ASSERT_EQ(Element::string, hash->getType()); + // SHA-256 -> 64 hex digits. + EXPECT_EQ(64, hash->stringValue().size()); +} + // Verify that the "config-test" command will do what we expect. TEST_F(CtrlChannelD2Test, configTest) { diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index b18f9dd914..e4631db699 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -85,6 +85,7 @@ public: /// - config-reload /// - config-set /// - config-get + /// - config-hash-get /// - config-test /// - dhcp-disable /// - dhcp-enable diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 3dfb9b4cb5..13c978e5ac 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -292,6 +294,27 @@ ControlledDhcpv6Srv::commandConfigGetHandler(const string&, return (createAnswer(CONTROL_RESULT_SUCCESS, config)); } +ConstElementPtr +ControlledDhcpv6Srv::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 ControlledDhcpv6Srv::commandConfigWriteHandler(const string&, ConstElementPtr args) { @@ -842,6 +865,9 @@ ControlledDhcpv6Srv::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)); @@ -1162,6 +1188,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_P CommandMgr::instance().registerCommand("config-get", std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand("config-hash-get", + std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2)); + CommandMgr::instance().registerCommand("config-reload", std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2)); @@ -1258,6 +1287,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() { 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/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h index 5271ace747..756c7d6e8c 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.h +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h @@ -85,6 +85,7 @@ public: /// - config-reload /// - config-set /// - config-get + /// - config-hash-get /// - config-test /// - dhcp-disable /// - dhcp-enable @@ -193,9 +194,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 +206,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/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index d1ed521713..a0cd3fce0e 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -576,6 +576,7 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) { EXPECT_TRUE(command_list.find("\"build-report\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-backend-pull\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"config-hash-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-set\"") != string::npos); EXPECT_TRUE(command_list.find("\"config-write\"") != string::npos); EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos); @@ -829,6 +830,33 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configGet) { EXPECT_TRUE(cfg->get("Dhcp6")->get("loggers")); } +// Tests if the server returns the hash of its configuration using +// config-hash-get. +TEST_F(CtrlChannelDhcpv6SrvTest, configHashGet) { + createUnixChannelServer(); + std::string response; + + sendUnixCommand("{ \"command\": \"config-hash-get\" }", response); + ConstElementPtr rsp; + + // The response should be a valid JSON. + EXPECT_NO_THROW(rsp = Element::fromJSON(response)); + ASSERT_TRUE(rsp); + + int status; + ConstElementPtr args = parseAnswer(status, rsp); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status); + + // Ok, now roughly check if the response seems legit. + ASSERT_TRUE(args); + ASSERT_EQ(Element::map, args->getType()); + ConstElementPtr hash = args->get("hash"); + ASSERT_TRUE(hash); + ASSERT_EQ(Element::string, hash->getType()); + // SHA-256 -> 64 hex digits. + EXPECT_EQ(64, hash->stringValue().size()); +} + // Verify that the "config-test" command will do what we expect. TEST_F(CtrlChannelDhcpv6SrvTest, configTest) { createUnixChannelServer(); @@ -1447,6 +1475,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, listCommands) { checkListCommands(rsp, "build-report"); checkListCommands(rsp, "config-backend-pull"); checkListCommands(rsp, "config-get"); + checkListCommands(rsp, "config-hash-get"); checkListCommands(rsp, "config-reload"); checkListCommands(rsp, "config-set"); checkListCommands(rsp, "config-test");