mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[3874] Added DUID configuration parser.
This commit is contained in:
@@ -139,6 +139,8 @@ libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.cc
|
||||
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
|
||||
|
133
src/lib/dhcpsrv/parsers/duid_config_parser.cc
Normal file
133
src/lib/dhcpsrv/parsers/duid_config_parser.cc
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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
|
87
src/lib/dhcpsrv/parsers/duid_config_parser.h
Normal file
87
src/lib/dhcpsrv/parsers/duid_config_parser.h
Normal file
@@ -0,0 +1,87 @@
|
||||
// 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
|
@@ -84,6 +84,7 @@ libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc
|
||||
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
|
||||
|
@@ -93,6 +93,8 @@ TEST(CfgDUIDTest, setIdentifier) {
|
||||
<< 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.
|
||||
|
214
src/lib/dhcpsrv/tests/duid_config_parser_unittest.cc
Normal file
214
src/lib/dhcpsrv/tests/duid_config_parser_unittest.cc
Normal file
@@ -0,0 +1,214 @@
|
||||
// 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
|
Reference in New Issue
Block a user