libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.cc
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.h
+libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.cc
+libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.cc
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <cc/data.h>
+#include <dhcp/duid.h>
+#include <dhcpsrv/cfg_duid.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/duid_config_parser.h>
+#include <exceptions/exceptions.h>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <limits>
+#include <string>
+
+using namespace isc::data;
+
+namespace isc {
+namespace dhcp {
+
+DUIDConfigParser::DUIDConfigParser()
+ : DhcpConfigParser() {
+}
+
+void
+DUIDConfigParser::build(isc::data::ConstElementPtr duid_configuration) {
+ bool type_present = false;
+ BOOST_FOREACH(ConfigPair element, duid_configuration->mapValue()) {
+ try {
+ if (element.first == "type") {
+ type_present = true;
+ setType(element.second->stringValue());
+ } else if (element.first == "identifier") {
+ setIdentifier(element.second->stringValue());
+ } else if (element.first == "htype") {
+ setHType(element.second->intValue());
+ } else if (element.first == "time") {
+ setTime(element.second->intValue());
+ } else if (element.first == "enterprise-id") {
+ setEnterpriseId(element.second->intValue());
+ } else {
+ isc_throw(DhcpConfigError, "unsupported configuration "
+ "parameter '" << element.first << "'");
+ }
+ } catch (const std::exception& ex) {
+ // Append position.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << element.second->getPosition() << ")");
+ }
+ }
+
+ // "type" is mandatory
+ if (!type_present) {
+ isc_throw(DhcpConfigError, "mandatory parameter \"type\" not specified"
+ " for the DUID configuration ("
+ << duid_configuration->getPosition() << ")");
+ }
+}
+
+void
+DUIDConfigParser::setType(const std::string& duid_type) const {
+ // Map DUID type represented as text into numeric value.
+ DUID::DUIDType numeric_type = DUID::DUID_UNKNOWN;
+ if (duid_type == "LLT") {
+ numeric_type = DUID::DUID_LLT;
+ } else if (duid_type == "EN") {
+ numeric_type = DUID::DUID_EN;
+ } else if (duid_type == "LL") {
+ numeric_type = DUID::DUID_LL;
+ } else {
+ isc_throw(DhcpConfigError, "unsupported DUID type '"
+ << duid_type << "'. Expected: LLT, EN or LL");
+ }
+
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ cfg->setType(static_cast<DUID::DUIDType>(numeric_type));
+}
+
+void
+DUIDConfigParser::setIdentifier(const std::string& identifier) const {
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ cfg->setIdentifier(identifier);
+}
+
+void
+DUIDConfigParser::setHType(const int64_t htype) const {
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ checkRange<uint16_t>("htype", htype);
+ cfg->setHType(static_cast<uint16_t>(htype));
+
+}
+
+void
+DUIDConfigParser::setTime(const int64_t new_time) const {
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ checkRange<uint32_t>("time", new_time);
+ cfg->setTime(static_cast<uint32_t>(new_time));
+}
+
+void
+DUIDConfigParser::setEnterpriseId(const int64_t enterprise_id) const {
+ const CfgDUIDPtr& cfg = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ checkRange<uint32_t>("enterprise-id", enterprise_id);
+ cfg->setEnterpriseId(static_cast<uint32_t>(enterprise_id));
+}
+
+template<typename NumericType>
+void
+DUIDConfigParser::checkRange(const std::string& parameter_name,
+ const int64_t parameter_value) const {
+ if ((parameter_value < 0) ||
+ (parameter_value > std::numeric_limits<NumericType>::max())) {
+ isc_throw(DhcpConfigError, "out of range value '" << parameter_value
+ << "' specified for parameter '" << parameter_name
+ << "'; expected value in range of [0.."
+ << std::numeric_limits<NumericType>::max() << "]");
+ }
+}
+
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DUID_CONFIG_PARSER_H
+#define DUID_CONFIG_PARSER_H
+
+#include <cc/data.h>
+#include <dhcpsrv/parsers/dhcp_config_parser.h>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Parser for a single host reservation entry.
+class DUIDConfigParser : public DhcpConfigParser {
+public:
+
+ /// @brief Constructor.
+ DUIDConfigParser();
+
+ /// @brief Parses DUID configuration.
+ ///
+ /// @param duid_configuration Data element holding a map representing
+ /// DUID configuration.
+ ///
+ /// @throw DhcpConfigError If the configuration is invalid.
+ virtual void build(isc::data::ConstElementPtr duid_configuration);
+
+ /// @brief Commit, unused.
+ virtual void commit() { }
+
+private:
+
+ /// @brief Validate and set DUID type.
+ ///
+ /// @param duid_type DUID type in textfual format.
+ void setType(const std::string& duid_type) const;
+
+ /// @brief Validate and set identifier.
+ ///
+ /// @param identifier Identifier.
+ void setIdentifier(const std::string& identifier) const;
+
+ /// @brief Validate and set hardware type.
+ ///
+ /// @param htype Hardware type.
+ void setHType(const int64_t htype) const;
+
+ /// @brief Validate and set time value.
+ ///
+ /// @param new_time Time value to be used for DUID.
+ void setTime(const int64_t new_time) const;
+
+ /// @brief Validate and set enterprise id.
+ ///
+ /// @param enterprise_id Enterprise id.
+ void setEnterpriseId(const int64_t enterprise_id) const;
+
+ /// @brief Verifies if the specified parameter is in range.
+ ///
+ /// Each numeric value must be in range of [0 .. max_value], where
+ /// max_value is a maximum value for the numeric type used for this
+ /// parameter.
+ ///
+ /// @param parameter_name Parameter name.
+ /// @tparam Numeric type of the specified parameter.
+ template<typename NumericType>
+ void checkRange(const std::string& parameter_name,
+ const int64_t parameter_value) const;
+};
+
+}
+} // end of namespace isc
+
+#endif // DUID_CONFIG_PARSER_H
libdhcpsrv_unittests_SOURCES += daemon_unittest.cc
libdhcpsrv_unittests_SOURCES += database_connection_unittest.cc
libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
+libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += host_unittest.cc
<< toString(cfg_duid.getIdentifier());
}
+// This test verifies that the invalid identifier is rejected and
+// exception is thrown.
TEST(CfgDUIDTest, setInvalidIdentifier) {
CfgDUID cfg_duid;
// Check that hexadecimal characters may be lower case.
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/cfg_duid.h>
+#include <dhcpsrv/parsers/duid_config_parser.h>
+#include <dhcpsrv/testutils/config_result_check.h>
+#include <util/encode/hex.h>
+#include <gtest/gtest.h>
+#include <limits>
+#include <sstream>
+#include <string>
+
+using namespace isc;
+using namespace isc::data;
+using namespace isc::dhcp;
+
+namespace {
+
+/// @brief Test fixture class for @c DUIDConfigParser
+class DUIDConfigParserTest : public ::testing::Test {
+public:
+
+ /// @brief Creates simple configuration with DUID type only.
+ ///
+ /// @param duid_type DUID type in the textual format.
+ std::string createConfigWithType(const std::string& duid_type) const;
+
+ /// @brief Creates simple configuration with DUID type and one
+ /// numeric parameter.
+ ///
+ /// @param name Parameter name.
+ /// @param value Parameter value.
+ std::string createConfigWithInteger(const std::string& name,
+ const int64_t value) const;
+
+ /// @brief Parse configuration.
+ ///
+ /// @param config String representing DUID configuration.
+ void build(const std::string& config) const;
+
+ /// @brief Test that only a DUID type can be specified.
+ ///
+ /// @param duid_type DUID type in numeric format.
+ /// @param duid_type_text DUID type in textual format.
+ void testTypeOnly(const DUID::DUIDType& duid_type,
+ const std::string duid_type_text) const;
+
+ /// @brief Test that invalid configuration is rejected.
+ ///
+ /// @param config Holds JSON configuration to be used.
+ void testInvalidConfig(const std::string& config) const;
+
+ /// @brief Test out of range numeric values.
+ ///
+ /// @param param_name Parameter name.
+ /// @tparam Type of the numeric parameter.
+ template<typename NumericType>
+ void testOutOfRange(const std::string& param_name) {
+ // Obtain maximum value for the specified numeric type.
+ const uint64_t max_value = std::numeric_limits<NumericType>::max();
+
+ // Negative values are not allowed.
+ EXPECT_THROW(build(createConfigWithInteger(param_name, -1)),
+ DhcpConfigError);
+ // Zero is allowed.
+ EXPECT_NO_THROW(build(createConfigWithInteger(param_name, 0)));
+ // Maximum value.
+ EXPECT_NO_THROW(build(createConfigWithInteger(param_name, max_value)));
+ // Value greater than maximum should result in exception.
+ EXPECT_THROW(build(createConfigWithInteger(param_name, max_value + 1)),
+ DhcpConfigError);
+ }
+
+ /// @brief Converts vector to string of hexadecimal digits.
+ ///
+ /// @param vec Input vector.
+ /// @return String of hexadecimal digits converted from vector.
+ std::string toString(const std::vector<uint8_t>& vec) const;
+};
+
+std::string
+DUIDConfigParserTest::createConfigWithType(const std::string& duid_type) const {
+ std::ostringstream s;
+ s << "{ \"type\": \"" << duid_type << "\" }";
+ return (s.str());
+}
+
+std::string
+DUIDConfigParserTest::createConfigWithInteger(const std::string& name,
+ const int64_t value) const {
+ std::ostringstream s;
+ s << "{ \"type\": \"LLT\", \"" << name << "\": " << value << " }";
+ return (s.str());
+}
+
+void
+DUIDConfigParserTest::build(const std::string& config) const {
+ ElementPtr config_element = Element::fromJSON(config);
+ DUIDConfigParser parser;
+ parser.build(config_element);
+}
+
+
+void
+DUIDConfigParserTest::testTypeOnly(const DUID::DUIDType& duid_type,
+ const std::string duid_type_text) const {
+ // Use DUID configuration with only a "type".
+ ASSERT_NO_THROW(build(createConfigWithType(duid_type_text)));
+
+ // Make sure that the type is correct and that other parameters are set
+ // to their defaults.
+ CfgDUIDPtr cfg_duid = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ EXPECT_EQ(duid_type, cfg_duid->getType());
+ EXPECT_TRUE(cfg_duid->getIdentifier().empty());
+ EXPECT_EQ(0, cfg_duid->getHType());
+ EXPECT_EQ(0, cfg_duid->getTime());
+ EXPECT_EQ(0, cfg_duid->getEnterpriseId());
+}
+
+void
+DUIDConfigParserTest::testInvalidConfig(const std::string& config) const {
+ EXPECT_THROW(build(config), DhcpConfigError);
+}
+
+std::string
+DUIDConfigParserTest::toString(const std::vector<uint8_t>& vec) const {
+ try {
+ return (util::encode::encodeHex(vec));
+ } catch (...) {
+ ADD_FAILURE() << "toString: unable to encode vector to"
+ " hexadecimal string";
+ }
+ return ("");
+}
+
+// This test verifies that it is allowed to specify a DUID-LLT type.
+TEST_F(DUIDConfigParserTest, typeOnlyLLT) {
+ testTypeOnly(DUID::DUID_LLT, "LLT");
+}
+
+// This test verifies that it is allowed to specify a DUID-EN type.
+TEST_F(DUIDConfigParserTest, typeOnlyEN) {
+ testTypeOnly(DUID::DUID_EN, "EN");
+}
+
+// This test verifies that it is allowed to specify a DUID-LL type.
+TEST_F(DUIDConfigParserTest, typeOnlyLL) {
+ testTypeOnly(DUID::DUID_LL, "LL");
+}
+
+// This test verifies that using unsupported DUID type will result in
+// configuration error.
+TEST_F(DUIDConfigParserTest, typeInvalid) {
+ testInvalidConfig(createConfigWithType("WRONG"));
+}
+
+// This test verifies that DUID type is required.
+TEST_F(DUIDConfigParserTest, noType) {
+ // First check that the configuration with DUID type specified is
+ // accepted.
+ ASSERT_NO_THROW(build("{ \"type\": \"LLT\", \"time\": 1 }"));
+ // Now remove the type and expect an error.
+ testInvalidConfig("{ \"time\": 1 }");
+}
+
+// This test verifies that all parameters can be set.
+TEST_F(DUIDConfigParserTest, allParameters) {
+ // Set all parameters.
+ ASSERT_NO_THROW(build("{ \"type\": \"EN\","
+ " \"identifier\": \"ABCDEF\","
+ " \"time\": 100,"
+ " \"htype\": 8,"
+ " \"enterprise-id\": 2024"
+ "}"));
+
+ // Verify that parameters have been set correctly.
+ CfgDUIDPtr cfg_duid = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+ EXPECT_EQ(DUID::DUID_EN, cfg_duid->getType());
+ EXPECT_EQ("ABCDEF", toString(cfg_duid->getIdentifier()));
+ EXPECT_EQ(8, cfg_duid->getHType());
+ EXPECT_EQ(100, cfg_duid->getTime());
+ EXPECT_EQ(2024, cfg_duid->getEnterpriseId());
+}
+
+// Test out of range values for time.
+TEST_F(DUIDConfigParserTest, timeOutOfRange) {
+ testOutOfRange<uint32_t>("time");
+}
+
+// Test out of range values for hardware type.
+TEST_F(DUIDConfigParserTest, htypeOutOfRange) {
+ testOutOfRange<uint16_t>("htype");
+}
+
+// Test out of range values for enterprise id.
+TEST_F(DUIDConfigParserTest, enterpriseIdOutOfRange) {
+ testOutOfRange<uint32_t>("enterprise-id");
+}
+
+} // end of anonymous namespace