Commit d508d4ac authored by Thomas Markwalder's avatar Thomas Markwalder

[3033] Added DHCP-DDNS configuration paramater parsing to b10-dhcp4

Added configuration paramters to dhcp4 and its spec file to support DHCP-DDNS.
Created new classes D2ClientMgr, D2ClientConfig, and D2CientConfigParser in the
libdhcpsrv.   The new parameters are parsed, validated, and stored  but do
not yet affect behavior.  That will be implemented as a seperate ticket.
parent be25b97a
......@@ -1365,6 +1365,7 @@ AC_CONFIG_FILES([compatcheck/Makefile
src/bin/dhcp4/spec_config.h.pre
src/bin/dhcp4/tests/Makefile
src/bin/dhcp4/tests/marker_file.h
src/bin/dhcp4/tests/test_data_files_config.h
src/bin/dhcp4/tests/test_libraries.h
src/bin/dhcp6/Makefile
src/bin/dhcp6/spec_config.h.pre
......
......@@ -396,6 +396,8 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("echo-client-id") == 0) {
parser = new BooleanParser(config_id, globalContext()->boolean_values_);
} else if (config_id.compare("dhcp-ddns") == 0) {
parser = new D2ClientConfigParser(config_id);
} else {
isc_throw(NotImplemented,
"Parser error: Global configuration parameter not supported: "
......@@ -448,7 +450,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Some of the parsers alter the state of the system in a way that can't
// easily be undone. (Or alter it in a way such that undoing the change has
// the same risk of failure as doing the change.)
ParserPtr hooks_parser_;
ParserPtr hooks_parser;
// The subnet parsers implement data inheritance by directly
// accessing global storage. For this reason the global data
......@@ -489,7 +491,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Executing commit will alter currently-loaded hooks
// libraries. Check if the supplied libraries are valid,
// but defer the commit until everything else has committed.
hooks_parser_ = parser;
hooks_parser = parser;
parser->build(config_pair.second);
} else {
// Those parsers should be started before other
......@@ -557,8 +559,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// This occurs last as if it succeeds, there is no easy way
// revert it. As a result, the failure to commit a subsequent
// change causes problems when trying to roll back.
if (hooks_parser_) {
hooks_parser_->commit();
if (hooks_parser) {
hooks_parser->commit();
}
}
catch (const isc::Exception& ex) {
......
......@@ -292,7 +292,110 @@
}
} ]
}
}
},
{ "item_name": "dhcp-ddns",
"item_type": "map",
"item_optional": false,
"item_default": {"enable-updates": false},
"map_item_spec": [
{
"item_name": "enable-updates",
"item_type": "boolean",
"item_optional": false,
"item_default": False,
"item_description" : "Enables DDNS update processing"
},
{
"item_name": "server_ip",
"item_type": "string",
"item_optional": true,
"item_default": "127.0.0.1",
"item_description" : "IP address of b10-dhcp-ddns"
},
{
"item_name": "server_port",
"item_type": "integer",
"item_optional": true,
"item_default": 5301,
"item_description" : "port number of b10-dhcp-ddns"
},
{
"item_name": "ncr_protocol",
"item_type": "string",
"item_optional": true,
"item_default": "UDP",
"item_description" : "Socket protocol to use with b10-dhcp-ddns"
},
{
"item_name": "ncr_format",
"item_type": "string",
"item_optional": true,
"item_default": "JSON",
"item_description" : "Format of the update request packet"
},
{
"item_name": "remove-on-renew",
"item_type": "boolean",
"item_optional": true,
"item_default": false,
"item_description": "Should server request a DNS Remove, before a DNS Update on renewals"
},
{
"item_name": "always-include-fqdn",
"item_type": "boolean",
"item_optional": true,
"item_default": False,
"item_description": "Should server always include the FQDN option in its response"
},
{
"item_name": "allow-client-update",
"item_type": "boolean",
"item_optional": true,
"item_default": False,
"item_description": "Enable AAAA RR update delegation to the client"
},
{
"item_name": "override-no-update",
"item_type": "boolean",
"item_optional": true,
"item_default": false,
"item_description": "Do update, even if client requested no updates with N flag"
},
{
"item_name": "override-client-update",
"item_type": "boolean",
"item_optional": true,
"item_default": true,
"item_description": "Server performs an update even if client requested delegation"
},
{
"item_name": "replace-client-name",
"item_type": "boolean",
"item_optional": true,
"item_default": false,
"item_description": "Should server replace the domain-name supplied by the client"
},
{
"item_name": "generated-prefix",
"item_type": "string",
"item_optional": true,
"item_default": "myhost",
"item_description": "Prefix to use when generating the client's name"
},
{
"item_name": "qualifying-suffix",
"item_type": "string",
"item_optional": true,
"item_default": "example.com",
"item_description": "Fully qualified domain-name suffix if partial name provided by client"
},
]
},
],
"commands": [
{
......
......@@ -30,6 +30,7 @@
#include "marker_file.h"
#include "test_libraries.h"
#include "test_data_files_config.h"
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
......@@ -50,6 +51,22 @@ using namespace std;
namespace {
/// @brief Prepends the given name with the DHCP4 source directory
///
/// @param name file name of the desired file
/// @return string containing the absolute path of the file in the DHCP source
/// directory.
std::string specfile(const std::string& name) {
return (std::string(DHCP4_SRC_DIR) + "/" + name);
}
/// @brief Tests that the spec file is valid.
/// Verifies that the BIND10 DHCP-DDNS configuration specification file
// is valid.
TEST(Dhcp4SpecTest, basicSpec) {
ASSERT_NO_THROW(isc::config::moduleSpecFromFile(specfile("dhcp4.spec")));
}
class Dhcp4ParserTest : public ::testing::Test {
public:
Dhcp4ParserTest()
......@@ -321,6 +338,7 @@ public:
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000, "
"\"subnet4\": [ ], "
"\"dhcp-ddns\": { \"enable-updates\" : false }, "
"\"option-def\": [ ], "
"\"option-data\": [ ] }";
static_cast<void>(executeConfiguration(config,
......@@ -2299,6 +2317,117 @@ TEST_F(Dhcp4ParserTest, allInterfaces) {
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
}
// This test checks the ability of the server to parse a configuration
// containing a full, valid dhcp-ddns (D2ClientConfig) entry.
TEST_F(Dhcp4ParserTest, d2ClientConfig) {
ConstElementPtr status;
// Verify that the D2 configuraiton can be fetched and is set to disabled.
D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
EXPECT_FALSE(d2_client_config->getEnableUpdates());
// Verify that the convenience method agrees.
ASSERT_FALSE(CfgMgr::instance().isDhcpDdnsEnabled());
string config_str = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
" \"subnet\": \"192.0.2.0/24\" } ],"
" \"dhcp-ddns\" : {"
" \"enable-updates\" : true, "
" \"server-ip\" : \"192.168.2.1\", "
" \"server-port\" : 5301, "
" \"ncr-protocol\" : \"UDP\", "
" \"ncr-format\" : \"JSON\", "
" \"remove-on-renew\" : true, "
" \"always-include-fqdn\" : true, "
" \"allow-client-update\" : true, "
" \"override-no-update\" : true, "
" \"override-client-update\" : true, "
" \"replace-client-name\" : true, "
" \"generated-prefix\" : \"test.prefix\", "
" \"qualifying-suffix\" : \"test.suffix.\" },"
"\"valid-lifetime\": 4000 }";
// Convert the JSON string to configuration elements.
ElementPtr config;
ASSERT_NO_THROW(config = Element::fromJSON(config_str));
// Pass the configuration in for parsing.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));
// check if returned status is OK
checkResult(status, 0);
// Verify that DHCP-DDNS updating is enabled.
EXPECT_TRUE(CfgMgr::instance().isDhcpDdnsEnabled());
// Verify that the D2 configuration can be retrieved.
d2_client_config = CfgMgr::instance().getD2ClientConfig();
ASSERT_TRUE(d2_client_config);
// Verify that the configuration values are correct.
EXPECT_TRUE(d2_client_config->getEnableUpdates());
EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText());
EXPECT_EQ(5301, d2_client_config->getServerPort());
EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
EXPECT_TRUE(d2_client_config->getRemoveOnRenew());
EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());
EXPECT_TRUE(d2_client_config->getAllowClientUpdate());
EXPECT_TRUE(d2_client_config->getOverrideNoUpdate());
EXPECT_TRUE(d2_client_config->getOverrideClientUpdate());
EXPECT_TRUE(d2_client_config->getReplaceClientName());
EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
}
// This test checks the ability of the server to handle a configuration
// containing an invalid dhcp-ddns (D2ClientConfig) entry.
TEST_F(Dhcp4ParserTest, invalidD2ClientConfig) {
ConstElementPtr status;
// Configuration string with an invalid D2 client config,
// "server-ip" is missing.
string config_str = "{ \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
" \"subnet\": \"192.0.2.0/24\" } ],"
" \"dhcp-ddns\" : {"
" \"enable-updates\" : true, "
" \"server-port\" : 5301, "
" \"ncr-protocol\" : \"UDP\", "
" \"ncr-format\" : \"JSON\", "
" \"remove-on-renew\" : true, "
" \"always-include-fqdn\" : true, "
" \"allow-client-update\" : true, "
" \"override-no-update\" : true, "
" \"override-client-update\" : true, "
" \"replace-client-name\" : true, "
" \"generated-prefix\" : \"test.prefix\", "
" \"qualifying-suffix\" : \"test.suffix.\" },"
"\"valid-lifetime\": 4000 }";
// Convert the JSON string to configuration elements.
ElementPtr config;
ASSERT_NO_THROW(config = Element::fromJSON(config_str));
// Configuration should not throw, but should fail.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, config));
// check if returned status is failed.
checkResult(status, 1);
// Verify that the D2 configuraiton can be fetched and is set to disabled.
D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
EXPECT_FALSE(d2_client_config->getEnableUpdates());
// Verify that the convenience method agrees.
ASSERT_FALSE(CfgMgr::instance().isDhcpDdnsEnabled());
}
}
// Copyright (C) 2013 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.
/// @brief Path to dhcp4 source dir so tests against the dhcp4.spec file
/// can find it reliably.
#define DHCP4_SRC_DIR "@abs_top_srcdir@/src/bin/dhcp4"
......@@ -18,6 +18,32 @@
namespace isc {
namespace dhcp_ddns {
NameChangeProtocol stringToNcrProtocol(const std::string& protocol_str) {
if (protocol_str == "UDP") {
return NCR_UDP;
}
if (protocol_str == "TCP") {
return NCR_TCP;
}
isc_throw(BadValue, "Invalid NameChangeRequest protocol:" << protocol_str);
}
std::string ncrProtocolToString(NameChangeProtocol protocol) {
switch (protocol) {
case NCR_UDP:
return ("UDP");
case NCR_TCP:
return ("TCP");
default:
break;
}
return ("UNKNOWN");
}
//************************** NameChangeListener ***************************
NameChangeListener::NameChangeListener(RequestReceiveHandler&
......
......@@ -66,6 +66,31 @@
namespace isc {
namespace dhcp_ddns {
/// @brief Defines the list of socket protocols supported.
enum NameChangeProtocol {
NCR_UDP,
NCR_TCP
};
/// @brief Function which converts labels to NameChangeProtocol enum values.
///
/// @param protocol_str text to convert to an enum.
/// Valid string values: "UDP", "TCP"
///
/// @return NameChangeProtocol value which maps to the given string.
///
/// @throw isc::BadValue if given a string value which does not map to an
/// enum value.
extern NameChangeProtocol stringToNcrProtocol(const std::string& protocol_str);
/// @brief Function which converts NameChangeProtocol enums to text labels.
///
/// @param protocol enum value to convert to label
///
/// @return std:string containing the text label if the value is valid, or
/// "UNKNOWN" if not.
extern std::string ncrProtocolToString(NameChangeProtocol protocol);
/// @brief Exception thrown if an NcrListenerError encounters a general error.
class NcrListenerError : public isc::Exception {
public:
......
......@@ -26,6 +26,22 @@
namespace isc {
namespace dhcp_ddns {
NameChangeFormat stringToNcrFormat(const std::string& fmt_str) {
if (fmt_str == "JSON") {
return FMT_JSON;
}
isc_throw(BadValue, "Invalid NameChangeRequest format:" << fmt_str);
}
std::string ncrFormatToString(NameChangeFormat format) {
if (format == FMT_JSON) {
return ("JSON");
}
return ("UNKNOWN");
}
/********************************* D2Dhcid ************************************/
......
......@@ -70,6 +70,25 @@ enum NameChangeFormat {
FMT_JSON
};
/// @brief Function which converts labels to NameChangeFormat enum values.
///
/// @param format_str text to convert to an enum.
/// Valid string values: "JSON"
///
/// @return NameChangeFormat value which maps to the given string.
///
/// @throw isc::BadValue if given a string value which does not map to an
/// enum value.
extern NameChangeFormat stringToNcrFormat(const std::string& fmt_str);
/// @brief Function which converts NameChangeFormat enums to text labels.
///
/// @param format enum value to convert to label
///
/// @return std:string containing the text label if the value is valid, or
/// "UNKNOWN" if not.
extern std::string ncrFormatToString(NameChangeFormat format);
/// @brief Container class for handling the DHCID value within a
/// NameChangeRequest. It provides conversion to and from string for JSON
/// formatting, but stores the data internally as unsigned bytes.
......
......@@ -12,7 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcp_ddns/ncr_msg.h>
#include <dhcp_ddns/ncr_io.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <util/time_utilities.h>
......@@ -608,5 +608,23 @@ TEST(NameChangeRequestTest, ipAddresses) {
ASSERT_THROW(ncr.setIpAddress("x001:1::f3"),NcrMessageError);
}
/// @brief Tests conversion of NameChangeFormat between enum and strings.
TEST(NameChangeFormatTest, formatEnumConversion){
ASSERT_EQ(stringToNcrFormat("JSON"), dhcp_ddns::FMT_JSON);
ASSERT_THROW(stringToNcrFormat("bogus"), isc::BadValue);
ASSERT_EQ(ncrFormatToString(dhcp_ddns::FMT_JSON), "JSON");
}
/// @brief Tests conversion of NameChangeProtocol between enum and strings.
TEST(NameChangeProtocolTest, protocolEnumConversion){
ASSERT_EQ(stringToNcrProtocol("UDP"), dhcp_ddns::NCR_UDP);
ASSERT_EQ(stringToNcrProtocol("TCP"), dhcp_ddns::NCR_TCP);
ASSERT_THROW(stringToNcrProtocol("bogus"), isc::BadValue);
ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_UDP), "UDP");
ASSERT_EQ(ncrProtocolToString(dhcp_ddns::NCR_TCP), "TCP");
}
} // end of anonymous namespace
......@@ -39,6 +39,7 @@ libb10_dhcpsrv_la_SOURCES =
libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libb10_dhcpsrv_la_SOURCES += callout_handle_store.h
libb10_dhcpsrv_la_SOURCES += d2_client.cc d2_client.h
libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
libb10_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
......@@ -64,6 +65,7 @@ libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/hooks/libb10-hooks.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
......
......@@ -348,9 +348,26 @@ CfgMgr::getUnicast(const std::string& iface) const {
return (&(*addr).second);
}
void
CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
d2_client_mgr_.setD2ClientConfig(new_config);
}
bool
CfgMgr::isDhcpDdnsEnabled() {
return (d2_client_mgr_.isDhcpDdnsEnabled());
}
const D2ClientConfigPtr&
CfgMgr::getD2ClientConfig() const {
return (d2_client_mgr_.getD2ClientConfig());
}
CfgMgr::CfgMgr()
: datadir_(DHCP_DATA_DIR),
all_ifaces_active_(false), echo_v4_client_id_(true) {
all_ifaces_active_(false), echo_v4_client_id_(true),
d2_client_mgr_() {
// DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
// Note: the definition of DHCP_DATA_DIR needs to include quotation marks
// See AM_CPPFLAGS definition in Makefile.am
......
......@@ -19,6 +19,7 @@
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcp/option_space.h>
#include <dhcpsrv/d2_client.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
......@@ -332,6 +333,24 @@ public:
return (echo_v4_client_id_);
}
/// @brief Updates the DHCP-DDNS client configuration to the given value.
///
/// @param new_config pointer to the new client configuration.
///
/// @throw Underlying method(s) will throw D2ClientError if given an empty
/// pointer.
void setD2ClientConfig(D2ClientConfigPtr& new_config);
/// @param Convenience method for checking if DHCP-DDNS updates are enabled.
///
/// @return True if the D2 configuration is enabled.
bool isDhcpDdnsEnabled();
/// @brief Fetches the DHCP-DDNS configuration pointer.
///
/// @return a reference to the current configuration pointer.
const D2ClientConfigPtr& getD2ClientConfig() const;
protected:
/// @brief Protected constructor.
......@@ -411,6 +430,9 @@ private:
/// Indicates whether v4 server should send back client-id
bool echo_v4_client_id_;
/// @brief Manages the DHCP-DDNS client and its configuration.
D2ClientMgr d2_client_mgr_;
};
} // namespace isc::dhcp
......
// Copyright (C) 2013 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 <dhcpsrv/d2_client.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <string>
using namespace std;
namespace isc {
namespace dhcp {
D2ClientConfig::D2ClientConfig(const bool enable_updates,
const isc::asiolink::IOAddress& server_ip,
const size_t server_port,
const dhcp_ddns::
NameChangeProtocol& ncr_protocol,
const dhcp_ddns::
NameChangeFormat& ncr_format,
const bool remove_on_renew,
const bool always_include_fqdn,
const bool allow_client_update,
const bool override_no_update,
const bool override_client_update,
const bool replace_client_name,
const std::string& generated_prefix,
const std::string& qualifying_suffix)
: enable_updates_(enable_updates),
server_ip_(server_ip.getAddress()),
server_port_(server_port),
ncr_protocol_(ncr_protocol),
ncr_format_(ncr_format),
remove_on_renew_(remove_on_renew),
always_include_fqdn_(always_include_fqdn),
allow_client_update_(allow_client_update),
override_no_update_(override_no_update),
override_client_update_(override_client_update),
replace_client_name_(replace_client_name),
generated_prefix_(generated_prefix),
qualifying_suffix_(qualifying_suffix) {
if (ncr_format_ != dhcp_ddns::FMT_JSON) {
isc_throw(D2ClientError, "D2ClientConfig: NCR Format:"
<< dhcp_ddns::ncrFormatToString(ncr_format)
<< " is not yet supported");
}
if (ncr_protocol_ != dhcp_ddns::NCR_UDP) {
isc_throw(D2ClientError, "D2ClientConfig: NCR Protocol:"
<< dhcp_ddns::ncrProtocolToString(ncr_protocol)
<< " is not yet supported");
}
// @todo perhaps more validation we should do yet?
// Are there any invalid combinations of options we need to test against?
// For instance are allow_client_update and override_client_update mutually
// exclusive?
// Also do we care about validating contents if it's disabled?
}
D2ClientConfig::D2ClientConfig()
: enable_updates_(false),
server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
server_port_(0),
ncr_protocol_(dhcp_ddns::NCR_UDP),