summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcpsrv')
-rw-r--r--src/lib/dhcpsrv/.gitignore1
-rw-r--r--src/lib/dhcpsrv/Makefile.am2
-rw-r--r--src/lib/dhcpsrv/alloc_engine.cc87
-rw-r--r--src/lib/dhcpsrv/alloc_engine.h35
-rw-r--r--src/lib/dhcpsrv/cfgmgr.cc27
-rw-r--r--src/lib/dhcpsrv/cfgmgr.h29
-rw-r--r--src/lib/dhcpsrv/d2_client.cc263
-rw-r--r--src/lib/dhcpsrv/d2_client.h382
-rw-r--r--src/lib/dhcpsrv/dbaccess_parser.h3
-rw-r--r--src/lib/dhcpsrv/dhcp_parsers.cc133
-rw-r--r--src/lib/dhcpsrv/dhcp_parsers.h76
-rw-r--r--src/lib/dhcpsrv/dhcpsrv_messages.mes3
-rw-r--r--src/lib/dhcpsrv/lease.cc13
-rw-r--r--src/lib/dhcpsrv/lease.h10
-rw-r--r--src/lib/dhcpsrv/lease_mgr.h2
-rw-r--r--src/lib/dhcpsrv/memfile_lease_mgr.cc4
-rw-r--r--src/lib/dhcpsrv/mysql_lease_mgr.cc4
-rw-r--r--src/lib/dhcpsrv/pool.cc8
-rw-r--r--src/lib/dhcpsrv/subnet.cc16
-rw-r--r--src/lib/dhcpsrv/subnet.h38
-rw-r--r--src/lib/dhcpsrv/tests/.gitignore1
-rw-r--r--src/lib/dhcpsrv/tests/Makefile.am5
-rw-r--r--src/lib/dhcpsrv/tests/alloc_engine_unittest.cc176
-rw-r--r--src/lib/dhcpsrv/tests/cfgmgr_unittest.cc48
-rw-r--r--src/lib/dhcpsrv/tests/d2_client_unittest.cc798
-rw-r--r--src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc275
-rw-r--r--src/lib/dhcpsrv/tests/lease_mgr_unittest.cc623
-rw-r--r--src/lib/dhcpsrv/tests/lease_unittest.cc694
-rw-r--r--src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc8
-rw-r--r--src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc24
-rw-r--r--src/lib/dhcpsrv/tests/test_utils.cc4
31 files changed, 3015 insertions, 777 deletions
diff --git a/src/lib/dhcpsrv/.gitignore b/src/lib/dhcpsrv/.gitignore
index 0b02c01a50..1f085382ce 100644
--- a/src/lib/dhcpsrv/.gitignore
+++ b/src/lib/dhcpsrv/.gitignore
@@ -1,2 +1,3 @@
/dhcpsrv_messages.cc
/dhcpsrv_messages.h
+/s-messages
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
index b3c420680f..69b14b2ee0 100644
--- a/src/lib/dhcpsrv/Makefile.am
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -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
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
index dd1481e9e1..11b0700e3a 100644
--- a/src/lib/dhcpsrv/alloc_engine.cc
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -90,7 +90,7 @@ AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress&
const uint8_t prefix_len) {
if (!prefix.isV6()) {
isc_throw(BadValue, "Prefix operations are for IPv6 only (attempted to "
- "increase prefix " << prefix.toText() << ")");
+ "increase prefix " << prefix << ")");
}
// Get a buffer holding an address.
@@ -294,11 +294,12 @@ AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts,
Lease6Collection
AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
- uint32_t iaid, const IOAddress& hint,
+ const uint32_t iaid, const IOAddress& hint,
Lease::Type type, const bool fwd_dns_update,
const bool rev_dns_update,
const std::string& hostname, bool fake_allocation,
- const isc::hooks::CalloutHandlePtr& callout_handle) {
+ const isc::hooks::CalloutHandlePtr& callout_handle,
+ Lease6Collection& old_leases) {
try {
AllocatorPtr allocator = getAllocator(type);
@@ -316,37 +317,49 @@ AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
isc_throw(InvalidOperation, "DUID is mandatory for allocation");
}
- // check if there's existing lease for that subnet/duid/iaid combination.
+ // Check if there's existing lease for that subnet/duid/iaid
+ // combination.
/// @todo: Make this generic (cover temp. addrs and prefixes)
Lease6Collection existing = LeaseMgrFactory::instance().getLeases6(type,
*duid, iaid, subnet->getID());
+ // There is at least one lease for this client. We will return these
+ // leases for the client, but we may need to update FQDN information.
if (!existing.empty()) {
- // we have at least one lease already. This is a returning client,
- // probably after his reboot.
- return (existing);
+ // Return old leases so the server can see what has changed.
+ old_leases = existing;
+ return (updateFqdnData(existing, fwd_dns_update, rev_dns_update,
+ hostname, fake_allocation));
}
// check if the hint is in pool and is available
// This is equivalent of subnet->inPool(hint), but returns the pool
- Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>(subnet->getPool(type, hint, false));
+ Pool6Ptr pool = boost::dynamic_pointer_cast<
+ Pool6>(subnet->getPool(type, hint, false));
if (pool) {
/// @todo: We support only one hint for now
Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(type, hint);
if (!lease) {
- /// @todo: check if the hint is reserved once we have host support
- /// implemented
-
- // the hint is valid and not currently used, let's create a lease for it
- lease = createLease6(subnet, duid, iaid, hint, pool->getLength(),
- type, fwd_dns_update, rev_dns_update,
+ /// @todo: check if the hint is reserved once we have host
+ /// support implemented
+
+ // The hint is valid and not currently used, let's create a
+ // lease for it
+ lease = createLease6(subnet, duid, iaid, hint,
+ pool->getLength(), type,
+ fwd_dns_update, rev_dns_update,
hostname, callout_handle, fake_allocation);
- // It can happen that the lease allocation failed (we could have lost
- // the race condition. That means that the hint is lo longer usable and
- // we need to continue the regular allocation path.
+ // It can happen that the lease allocation failed (we could
+ // have lost the race condition. That means that the hint is
+ // lo longer usable and we need to continue the regular
+ // allocation path.
if (lease) {
+ // We are allocating a new lease (not renewing). So, the
+ // old lease should be NULL.
+ old_leases.push_back(Lease6Ptr());
+
/// @todo: We support only one lease per ia for now
Lease6Collection collection;
collection.push_back(lease);
@@ -354,6 +367,11 @@ AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
}
} else {
if (lease->expired()) {
+ // Copy an existing, expired lease so as it can be returned
+ // to the caller.
+ Lease6Ptr old_lease(new Lease6(*lease));
+ old_leases.push_back(old_lease);
+
/// We found a lease and it is expired, so we can reuse it
lease = reuseExpiredLease(lease, subnet, duid, iaid,
pool->getLength(),
@@ -414,6 +432,10 @@ AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
rev_dns_update, hostname,
callout_handle, fake_allocation);
if (lease) {
+ // We are allocating a new lease (not renewing). So, the
+ // old lease should be NULL.
+ old_leases.push_back(Lease6Ptr());
+
Lease6Collection collection;
collection.push_back(lease);
return (collection);
@@ -424,6 +446,11 @@ AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
// allocation attempts.
} else {
if (existing->expired()) {
+ // Copy an existing, expired lease so as it can be returned
+ // to the caller.
+ Lease6Ptr old_lease(new Lease6(*existing));
+ old_leases.push_back(old_lease);
+
existing = reuseExpiredLease(existing, subnet, duid, iaid,
prefix_len, fwd_dns_update,
rev_dns_update, hostname,
@@ -1037,6 +1064,30 @@ Lease4Ptr AllocEngine::createLease4(const SubnetPtr& subnet,
}
}
+Lease6Collection
+AllocEngine::updateFqdnData(const Lease6Collection& leases,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
+ const bool fake_allocation) {
+ Lease6Collection updated_leases;
+ for (Lease6Collection::const_iterator lease_it = leases.begin();
+ lease_it != leases.end(); ++lease_it) {
+ Lease6Ptr lease(new Lease6(**lease_it));
+ lease->fqdn_fwd_ = fwd_dns_update;
+ lease->fqdn_rev_ = rev_dns_update;
+ lease->hostname_ = hostname;
+ if (!fake_allocation &&
+ ((lease->fqdn_fwd_ != (*lease_it)->fqdn_fwd_) ||
+ (lease->fqdn_rev_ != (*lease_it)->fqdn_rev_) ||
+ (lease->hostname_ != (*lease_it)->hostname_))) {
+ LeaseMgrFactory::instance().updateLease6(lease);
+ }
+ updated_leases.push_back(lease);
+ }
+ return (updated_leases);
+}
+
AllocEngine::AllocatorPtr AllocEngine::getAllocator(Lease::Type type) {
std::map<Lease::Type, AllocatorPtr>::const_iterator alloc = allocators_.find(type);
diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h
index 8299bb8512..ed2a767266 100644
--- a/src/lib/dhcpsrv/alloc_engine.h
+++ b/src/lib/dhcpsrv/alloc_engine.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -338,14 +338,21 @@ protected:
/// an address for SOLICIT that is not really allocated (true)
/// @param callout_handle a callout handle (used in hooks). A lease callouts
/// will be executed if this parameter is passed.
+ /// @param [out] old_leases Collection to which this function will append
+ /// old leases. Leases are stored in the same order as in the
+ /// collection of new leases, being returned. For newly allocated
+ /// leases (not renewed) the NULL pointers are stored in this
+ /// collection as old leases.
///
/// @return Allocated IPv6 leases (may be empty if allocation failed)
Lease6Collection
- allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid, uint32_t iaid,
+ allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ const uint32_t iaid,
const isc::asiolink::IOAddress& hint, Lease::Type type,
const bool fwd_dns_update, const bool rev_dns_update,
const std::string& hostname, bool fake_allocation,
- const isc::hooks::CalloutHandlePtr& callout_handle);
+ const isc::hooks::CalloutHandlePtr& callout_handle,
+ Lease6Collection& old_leases);
/// @brief returns allocator for a given pool type
/// @param type type of pool (V4, IA, TA or PD)
@@ -489,6 +496,28 @@ private:
const isc::hooks::CalloutHandlePtr& callout_handle,
bool fake_allocation = false);
+ /// @brief Updates FQDN data for a collection of leases.
+ ///
+ /// @param leases Collection of leases for which FQDN data should be
+ /// updated.
+ /// @param fwd_dns_update Boolean value which indicates whether forward FQDN
+ /// update was performed for each lease (true) or not (false).
+ /// @param rev_dns_update Boolean value which indicates whether reverse FQDN
+ /// update was performed for each lease (true) or not (false).
+ /// @param hostname Client hostname associated with a lease.
+ /// @param fake_allocation Boolean value which indicates that it is a real
+ /// lease allocation, e.g. Request message is processed (false), or address
+ /// is just being picked as a result of processing Solicit (true). In the
+ /// latter case, the FQDN data should not be updated in the lease database.
+ ///
+ /// @return Collection of leases with updated FQDN data. Note that returned
+ /// collection holds updated FQDN data even for fake allocation.
+ Lease6Collection updateFqdnData(const Lease6Collection& leases,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
+ const bool fake_allocation);
+
/// @brief a pointer to currently used allocator
///
/// For IPv4, there will be only one allocator: TYPE_V4
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index 7789c74454..798d508f12 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -152,7 +152,7 @@ CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
// configuration. Such requirement makes sense in IPv4, but not in IPv6.
// The server does not need to have a global address (using just link-local
// is ok for DHCPv6 server) from the pool it serves.
- if ((subnets6_.size() == 1) && hint.getAddress().to_v6().is_link_local()) {
+ if ((subnets6_.size() == 1) && hint.isV6LinkLocal()) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
DHCPSRV_CFGMGR_ONLY_SUBNET6)
.arg(subnets6_[0]->toText()).arg(hint.toText());
@@ -348,9 +348,30 @@ CfgMgr::getUnicast(const std::string& iface) const {
return (&(*addr).second);
}
+void
+CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
+ d2_client_mgr_.setD2ClientConfig(new_config);
+}
+
+bool
+CfgMgr::ddnsEnabled() {
+ return (d2_client_mgr_.ddnsEnabled());
+}
+
+const D2ClientConfigPtr&
+CfgMgr::getD2ClientConfig() const {
+ return (d2_client_mgr_.getD2ClientConfig());
+}
+
+D2ClientMgr&
+CfgMgr::getD2ClientMgr() {
+ return (d2_client_mgr_);
+}
+
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
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index cda59f2c58..18455d08f2 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -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,29 @@ 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);
+
+ /// @brief Convenience method for checking if DHCP-DDNS updates are enabled.
+ ///
+ /// @return True if the D2 configuration is enabled.
+ bool ddnsEnabled();
+
+ /// @brief Fetches the DHCP-DDNS configuration pointer.
+ ///
+ /// @return a reference to the current configuration pointer.
+ const D2ClientConfigPtr& getD2ClientConfig() const;
+
+ /// @brief Fetches the DHCP-DDNS manager.
+ ///
+ /// @return a reference to the DHCP-DDNS manager.
+ D2ClientMgr& getD2ClientMgr();
+
protected:
/// @brief Protected constructor.
@@ -411,6 +435,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
diff --git a/src/lib/dhcpsrv/d2_client.cc b/src/lib/dhcpsrv/d2_client.cc
new file mode 100644
index 0000000000..494c858937
--- /dev/null
+++ b/src/lib/dhcpsrv/d2_client.cc
@@ -0,0 +1,263 @@
+// Copyright (C) 2013-2014 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 always_include_fqdn,
+ 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),
+ server_port_(server_port),
+ ncr_protocol_(ncr_protocol),
+ ncr_format_(ncr_format),
+ always_include_fqdn_(always_include_fqdn),
+ 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) {
+ validateContents();
+}
+
+D2ClientConfig::D2ClientConfig()
+ : enable_updates_(false),
+ server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
+ server_port_(0),
+ ncr_protocol_(dhcp_ddns::NCR_UDP),
+ ncr_format_(dhcp_ddns::FMT_JSON),
+ always_include_fqdn_(false),
+ override_no_update_(false),
+ override_client_update_(false),
+ replace_client_name_(false),
+ generated_prefix_("myhost"),
+ qualifying_suffix_("example.com") {
+ validateContents();
+}
+
+D2ClientConfig::~D2ClientConfig(){};
+
+void
+D2ClientConfig::validateContents() {
+ 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?
+}
+
+bool
+D2ClientConfig::operator == (const D2ClientConfig& other) const {
+ return ((enable_updates_ == other.enable_updates_) &&
+ (server_ip_ == other.server_ip_) &&
+ (server_port_ == other.server_port_) &&
+ (ncr_protocol_ == other.ncr_protocol_) &&
+ (ncr_format_ == other.ncr_format_) &&
+ (always_include_fqdn_ == other.always_include_fqdn_) &&
+ (override_no_update_ == other.override_no_update_) &&
+ (override_client_update_ == other.override_client_update_) &&
+ (replace_client_name_ == other.replace_client_name_) &&
+ (generated_prefix_ == other.generated_prefix_) &&
+ (qualifying_suffix_ == other.qualifying_suffix_));
+}
+
+bool
+D2ClientConfig::operator != (const D2ClientConfig& other) const {
+ return (!(*this == other));
+}
+
+std::string
+D2ClientConfig::toText() const {
+ std::ostringstream stream;
+
+ stream << "enable_updates: " << (enable_updates_ ? "yes" : "no");
+ if (enable_updates_) {
+ stream << ", server_ip: " << server_ip_.toText()
+ << ", server_port: " << server_port_
+ << ", ncr_protocol: " << ncr_protocol_
+ << ", ncr_format: " << ncr_format_
+ << ", always_include_fqdn: " << (always_include_fqdn_ ?
+ "yes" : "no")
+ << ", override_no_update: " << (override_no_update_ ?
+ "yes" : "no")
+ << ", override_client_update: " << (override_client_update_ ?
+ "yes" : "no")
+ << ", replace_client_name: " << (replace_client_name_ ?
+ "yes" : "no")
+ << ", generated_prefix: [" << generated_prefix_ << "]"
+ << ", qualifying_suffix: [" << qualifying_suffix_ << "]";
+ }
+
+ return (stream.str());
+}
+
+std::ostream&
+operator<<(std::ostream& os, const D2ClientConfig& config) {
+ os << config.toText();
+ return (os);
+}
+
+D2ClientMgr::D2ClientMgr() : d2_client_config_(new D2ClientConfig()) {
+ // Default constructor initializes with a disabled configuration.
+}
+
+D2ClientMgr::~D2ClientMgr(){
+}
+
+void
+D2ClientMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
+ if (!new_config) {
+ isc_throw(D2ClientError,
+ "D2ClientMgr cannot set DHCP-DDNS configuration to NULL.");
+ }
+
+ // @todo When NameChangeSender is integrated, we will need to handle these
+ // scenarios:
+ // 1. D2 was enabled but now it is disabled
+ // - destroy the sender, flush any queued
+ // 2. D2 is still enabled but server parameters have changed
+ // - preserve any queued, reconnect based on sender parameters
+ // 3. D2 was was disabled now it is enabled.
+ // - create sender
+ //
+ // For now we just update the configuration.
+ d2_client_config_ = new_config;
+ LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_CFG_DHCP_DDNS)
+ .arg(!ddnsEnabled() ? "DHCP-DDNS updates disabled" :
+ "DHCP_DDNS updates enabled");
+}
+
+bool
+D2ClientMgr::ddnsEnabled() {
+ return (d2_client_config_->getEnableUpdates());
+}
+
+const D2ClientConfigPtr&
+D2ClientMgr::getD2ClientConfig() const {
+ return (d2_client_config_);
+}
+
+void
+D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
+ bool& server_s, bool& server_n) const {
+ // Per RFC 4702 & 4704, the client N and S flags allow the client to
+ // request one of three options:
+ //
+ // N flag S flag Option
+ // ------------------------------------------------------------------
+ // 0 0 client wants to do forward updates (section 3.2)
+ // 0 1 client wants server to do forward updates (section 3.3)
+ // 1 0 client wants no one to do updates (section 3.4)
+ // 1 1 invalid combination
+ // (Note section numbers cited are for 4702, for 4704 see 5.1, 5.2, and 5.3)
+ //
+ // Make a bit mask from the client's flags and use it to set the response
+ // flags accordingly.
+ const uint8_t mask = ((client_n ? 2 : 0) + (client_s ? 1 : 0));
+
+ switch (mask) {
+ case 0:
+ // If updates are enabled and we are overriding client delegation
+ // then S flag should be true.
+ server_s = (d2_client_config_->getEnableUpdates() &&
+ d2_client_config_->getOverrideClientUpdate());
+ break;
+
+ case 1:
+ server_s = d2_client_config_->getEnableUpdates();
+ break;
+
+ case 2:
+ // If updates are enabled and we are overriding "no updates" then
+ // S flag should be true.
+ server_s = (d2_client_config_->getEnableUpdates() &&
+ d2_client_config_->getOverrideNoUpdate());
+ break;
+
+ default:
+ // RFCs declare this an invalid combination.
+ isc_throw(isc::BadValue,
+ "Invalid client FQDN - N and S cannot both be 1");
+ break;
+ }
+
+ /// @todo Currently we are operating under the premise that N should be 1
+ /// if the server is not doing updates nor do we have configuration
+ /// controls to govern forward and reverse updates independently.
+ /// In addition, the client FQDN flags cannot explicitly suggest what to
+ /// do with reverse updates. They request either forward updates or no
+ /// updates. In other words, the client cannot request the server do or
+ /// not do reverse updates. For now, we are either going to do updates in
+ /// both directions or none at all. If and when additional configuration
+ /// parameters are added this logic will have to be reassessed.
+ server_n = !server_s;
+}
+
+std::string
+D2ClientMgr::generateFqdn(const asiolink::IOAddress& address) const {
+ std::string hostname = address.toText();
+ std::replace(hostname.begin(), hostname.end(),
+ (address.isV4() ? '.' : ':'), '-');
+
+ std::ostringstream gen_name;
+ gen_name << d2_client_config_->getGeneratedPrefix() << "-" << hostname;
+ return (qualifyName(gen_name.str()));
+}
+
+std::string
+D2ClientMgr::qualifyName(const std::string& partial_name) const {
+ std::ostringstream gen_name;
+ gen_name << partial_name << "." << d2_client_config_->getQualifyingSuffix();
+
+ // Tack on a trailing dot in case suffix doesn't have one.
+ std::string str = gen_name.str();
+ size_t len = str.length();
+ if ((len > 0) && (str[len - 1] != '.')) {
+ gen_name << ".";
+ }
+
+ return (gen_name.str());
+}
+
+
+
+}; // namespace dhcp
+}; // namespace isc
diff --git a/src/lib/dhcpsrv/d2_client.h b/src/lib/dhcpsrv/d2_client.h
new file mode 100644
index 0000000000..0a6faa4713
--- /dev/null
+++ b/src/lib/dhcpsrv/d2_client.h
@@ -0,0 +1,382 @@
+// Copyright (C) 2013-2014 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 D2_CLIENT_H
+#define D2_CLIENT_H
+
+/// @file d2_client.h Defines the D2ClientConfig and D2ClientMgr classes.
+/// This file defines the classes Kea uses to act as a client of the b10-
+/// dhcp-ddns module (aka D2).
+///
+#include <asiolink/io_address.h>
+#include <dhcp_ddns/ncr_io.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+
+/// An exception that is thrown if an error occurs while configuring
+/// the D2 DHCP DDNS client.
+class D2ClientError : public isc::Exception {
+public:
+
+ /// @brief constructor
+ ///
+ /// @param file name of the file, where exception occurred
+ /// @param line line of the file, where exception occurred
+ /// @param what text description of the issue that caused exception
+ D2ClientError(const char* file, size_t line, const char* what)
+ : isc::Exception(file, line, what) {}
+};
+
+/// @brief Acts as a storage vault for D2 client configuration
+///
+/// A simple container class for storing and retrieving the configuration
+/// parameters associated with DHCP-DDNS and acting as a client of D2.
+/// Instances of this class may be constructed through configuration parsing.
+///
+class D2ClientConfig {
+public:
+ /// @brief Constructor
+ ///
+ /// @param enable_updates Enables DHCP-DDNS updates
+ /// @param server_ip IP address of the b10-dhcp-ddns server (IPv4 or IPv6)
+ /// @param server_port IP port of the b10-dhcp-ddns server
+ /// @param ncr_protocol Socket protocol to use with b10-dhcp-ddns
+ /// Currently only UDP is supported.
+ /// @param ncr_format Format of the b10-dhcp-ddns requests.
+ /// Currently only JSON format is supported.
+ /// @param always_include_fqdn Enables always including the FQDN option in
+ /// DHCP responses.
+ /// @param override_no_update Enables updates, even if clients request no
+ /// updates.
+ /// @param override_client_update Perform updates, even if client requested
+ /// delegation.
+ /// @param replace_client_name enables replacement of the domain-name
+ /// supplied by the client with a generated name.
+ /// @param generated_prefix Prefix to use when generating domain-names.
+ /// @param qualifying_suffix Suffix to use to qualify partial domain-names.
+ ///
+ /// @throw D2ClientError if given an invalid protocol or format.
+ 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 always_include_fqdn,
+ 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);
+
+ /// @brief Default constructor
+ /// The default constructor creates an instance that has updates disabled.
+ D2ClientConfig();
+
+ /// @brief Destructor
+ virtual ~D2ClientConfig();
+
+ /// @brief Return whether or not DHCP-DDNS updating is enabled.
+ bool getEnableUpdates() const {
+ return(enable_updates_);
+ }
+
+ /// @brief Return the IP address of b10-dhcp-ddns (IPv4 or IPv6).
+ const isc::asiolink::IOAddress& getServerIp() const {
+ return(server_ip_);
+ }
+
+ /// @brief Return the IP port of b10-dhcp-ddns.
+ size_t getServerPort() const {
+ return(server_port_);
+ }
+
+ /// @brief Return the socket protocol to use with b10-dhcp-ddns.
+ const dhcp_ddns::NameChangeProtocol& getNcrProtocol() const {
+ return(ncr_protocol_);
+ }
+
+ /// @brief Return the b10-dhcp-ddns request format.
+ const dhcp_ddns::NameChangeFormat& getNcrFormat() const {
+ return(ncr_format_);
+ }
+
+ /// @brief Return whether or not FQDN is always included in DHCP responses.
+ bool getAlwaysIncludeFqdn() const {
+ return(always_include_fqdn_);
+ }
+
+ /// @brief Return if updates are done even if clients request no updates.
+ bool getOverrideNoUpdate() const {
+ return(override_no_update_);
+ }
+
+ /// @brief Return if updates are done even when clients request delegation.
+ bool getOverrideClientUpdate() const {
+ return(override_client_update_);
+ }
+
+ /// @brief Return whether or not client's domain-name is always replaced.
+ bool getReplaceClientName() const {
+ return(replace_client_name_);
+ }
+
+ /// @brief Return the prefix to use when generating domain-names.
+ const std::string& getGeneratedPrefix() const {
+ return(generated_prefix_);
+ }
+
+ /// @brief Return the suffix to use to qualify partial domain-names.
+ const std::string& getQualifyingSuffix() const {
+ return(qualifying_suffix_);
+ }
+
+ /// @brief Compares two D2ClientConfigs for equality
+ bool operator == (const D2ClientConfig& other) const;
+
+ /// @brief Compares two D2ClientConfigs for inequality
+ bool operator != (const D2ClientConfig& other) const;
+
+ /// @brief Generates a string representation of the class contents.
+ std::string toText() const;
+
+protected:
+ /// @brief Validates member values.
+ ///
+ /// Method is used by the constructor to validate member contents.
+ ///
+ /// @throw D2ClientError if given an invalid protocol or format.
+ virtual void validateContents();
+
+private:
+ /// @brief Indicates whether or not DHCP DDNS updating is enabled.
+ bool enable_updates_;
+
+ /// @brief IP address of the b10-dhcp-ddns server (IPv4 or IPv6).
+ isc::asiolink::IOAddress server_ip_;
+
+ /// @brief IP port of the b10-dhcp-ddns server.
+ size_t server_port_;
+
+ /// @brief The socket protocol to use with b10-dhcp-ddns.
+ /// Currently only UDP is supported.
+ dhcp_ddns::NameChangeProtocol ncr_protocol_;
+
+ /// @brief Format of the b10-dhcp-ddns requests.
+ /// Currently only JSON format is supported.
+ dhcp_ddns::NameChangeFormat ncr_format_;
+
+ /// @brief Should Kea always include the FQDN option in its response.
+ bool always_include_fqdn_;
+
+ /// @brief Should Kea perform updates, even if client requested no updates.
+ /// Overrides the client request for no updates via the N flag.
+ bool override_no_update_;
+
+ /// @brief Should Kea perform updates, even if client requested delegation.
+ bool override_client_update_;
+
+ /// @brief Should Kea replace the domain-name supplied by the client.
+ bool replace_client_name_;
+
+ /// @brief Prefix Kea should use when generating domain-names.
+ std::string generated_prefix_;
+
+ /// @brief Suffix Kea should use when to qualify partial domain-names.
+ std::string qualifying_suffix_;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const D2ClientConfig& config);
+
+/// @brief Defines a pointer for D2ClientConfig instances.
+typedef boost::shared_ptr<D2ClientConfig> D2ClientConfigPtr;
+
+/// @brief D2ClientMgr isolates Kea from the details of being a D2 client.
+///
+/// Provides services for managing the current D2ClientConfig and managing
+/// communications with D2. (@todo The latter will be added once communication
+/// with D2 is implemented through the integration of
+/// dhcp_ddns::NameChangeSender interface(s)).
+///
+class D2ClientMgr {
+public:
+ /// @brief Constructor
+ ///
+ /// Default constructor which constructs an instance which has DHCP-DDNS
+ /// updates disabled.
+ D2ClientMgr();
+
+ /// @brief Destructor.
+ ~D2ClientMgr();
+
+ /// @brief Updates the DHCP-DDNS client configuration to the given value.
+ ///
+ /// @param new_config pointer to the new client configuration.
+ /// @throw D2ClientError if passed an empty pointer.
+ void setD2ClientConfig(D2ClientConfigPtr& new_config);
+
+ /// @brief Convenience method for checking if DHCP-DDNS is enabled.
+ ///
+ /// @return True if the D2 configuration is enabled.
+ bool ddnsEnabled();
+
+ /// @brief Fetches the DHCP-DDNS configuration pointer.
+ ///
+ /// @return a reference to the current configuration pointer.
+ const D2ClientConfigPtr& getD2ClientConfig() const;
+
+ /// @brief Determines server flags based on configuration and client flags.
+ ///
+ /// This method uses input values for the client's FQDN S and N flags, in
+ /// conjunction with the configuration parameters updates-enabled, override-
+ /// no-updates, and override-client-updates to determine the values that
+ /// should be used for the server's FQDN S and N flags.
+ /// The logic in this method is based upon RFCs 4702 and 4704.
+ ///
+ /// @param client_s S Flag from the client's FQDN
+ /// @param client_n N Flag from the client's FQDN
+ /// @param server_s [out] S Flag for the server's FQDN
+ /// @param server_n [out] N Flag for the server's FQDN
+ ///
+ /// @throw isc::BadValue if client_s and client_n are both 1 as this is
+ /// an invalid combination per RFCs.
+ void analyzeFqdn(const bool client_s, const bool client_n, bool& server_s,
+ bool& server_n) const;
+
+ /// @brief Builds a FQDN based on the configuration and given IP address.
+ ///
+ /// Using the current values for generated-prefix, qualifying-suffix and
+ /// an IP address, this method constructs a fully qualified domain name.
+ /// It supports both IPv4 and IPv6 addresses. The format of the name
+ /// is as follows:
+ ///
+ /// <generated-prefix>-<ip address>.<qualifying-suffix>.
+ ///
+ /// <ip-address> is the result of IOAddress.toText() with the delimiters
+ /// ('.' for IPv4 or ':' for IPv6) replaced with a hyphen, '-'.
+ ///
+ /// @param address IP address from which to derive the name (IPv4 or IPv6)
+ ///
+ /// @return std::string containing the generated name.
+ std::string generateFqdn(const asiolink::IOAddress& address) const;
+
+ /// @brief Adds a qualifying suffix to a given domain name
+ ///
+ /// Constructs a FQDN based on the configured qualifying-suffix and
+ /// a partial domain name as follows:
+ ///
+ /// <partial_name>.<qualifying-suffix>.
+ /// Note it will add a trailing '.' should qualifying-suffix not end with
+ /// one.
+ ///
+ /// @param partial_name domain name to qualify
+ ///
+ /// @return std::string containing the qualified name.
+ std::string qualifyName(const std::string& partial_name) const;
+
+ /// @brief Set server FQDN flags based on configuration and a given FQDN
+ ///
+ /// Templated wrapper around the analyzeFqdn() allowing that method to
+ /// be used for either IPv4 or IPv6 processing. This methods resets all
+ /// of the flags in the response to zero and then sets the S,N, and O
+ /// flags. Any other flags are the responsiblity of the invoking layer.
+ ///
+ /// @param fqdn FQDN option from which to read client (inbound) flags
+ /// @param fqdn_resp FQDN option to update with the server (outbound) flags
+ /// @tparam T FQDN Option class containing the FQDN data such as
+ /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn
+ template <class T>
+ void adjustFqdnFlags(const T& fqdn, T& fqdn_resp);
+
+ /// @brief Set server FQDN name based on configuration and a given FQDN
+ ///
+ /// Templated method which adjusts the domain name value and type in
+ /// a server FQDN from a client (inbound) FQDN and the current
+ /// configuration. The logic is as follows:
+ ///
+ /// If replace-client-name is true or the supplied name is empty, the
+ /// server FQDN is set to ""/PARTIAL.
+ ///
+ /// If replace-client-name is false and the supplied name is a partial
+ /// name the server FQDN is set to the supplied name qualified by
+ /// appending the qualifying-suffix.
+ ///
+ /// If replace-client-name is false and the supplied name is a fully
+ /// qualified name, set the server FQDN to the supplied name.
+ ///
+ /// @param fqdn FQDN option from which to get client (inbound) name
+ /// @param fqdn_resp FQDN option to update with the adjusted name
+ /// @tparam T FQDN Option class containing the FQDN data such as
+ /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn
+ template <class T>
+ void adjustDomainName(const T& fqdn, T& fqdn_resp);
+
+private:
+ /// @brief Container class for DHCP-DDNS configuration parameters.
+ D2ClientConfigPtr d2_client_config_;
+};
+
+template <class T>
+void
+D2ClientMgr::adjustFqdnFlags(const T& fqdn, T& fqdn_resp) {
+ bool server_s = false;
+ bool server_n = false;
+ analyzeFqdn(fqdn.getFlag(T::FLAG_S), fqdn.getFlag(T::FLAG_N),
+ server_s, server_n);
+
+ // Reset the flags to zero to avoid triggering N and S both 1 check.
+ fqdn_resp.resetFlags();
+
+ // Set S and N flags.
+ fqdn_resp.setFlag(T::FLAG_S, server_s);
+ fqdn_resp.setFlag(T::FLAG_N, server_n);
+
+ // Set O flag true if server S overrides client S.
+ fqdn_resp.setFlag(T::FLAG_O, (fqdn.getFlag(T::FLAG_S) != server_s));
+}
+
+
+template <class T>
+void
+D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
+ // If we're configured to replace it or the supplied name is blank
+ // set the response name to blank.
+ if (d2_client_config_->getReplaceClientName() ||
+ fqdn.getDomainName().empty()) {
+ fqdn_resp.setDomainName("", T::PARTIAL);
+ } else {
+ // If the supplied name is partial, qualify it by adding the suffix.
+ if (fqdn.getDomainNameType() == T::PARTIAL) {
+ fqdn_resp.setDomainName(qualifyName(fqdn.getDomainName()), T::FULL);
+ }
+ }
+}
+
+/// @brief Defines a pointer for D2ClientMgr instances.
+typedef boost::shared_ptr<D2ClientMgr> D2ClientMgrPtr;
+
+
+} // namespace isc
+} // namespace dhcp
+
+#endif
diff --git a/src/lib/dhcpsrv/dbaccess_parser.h b/src/lib/dhcpsrv/dbaccess_parser.h
index 53e3f81ea3..77c984554d 100644
--- a/src/lib/dhcpsrv/dbaccess_parser.h
+++ b/src/lib/dhcpsrv/dbaccess_parser.h
@@ -94,7 +94,8 @@ public:
///
/// Creates an instance of this parser.
///
- /// @param name Name of the parameter used to access the configuration.
+ /// @param param_name Name of the parameter used to access the
+ /// configuration.
///
/// @return Pointer to a DbAccessParser. The caller is responsible for
/// destroying the parser after use.
diff --git a/src/lib/dhcpsrv/dhcp_parsers.cc b/src/lib/dhcpsrv/dhcp_parsers.cc
index ffd49d3083..7aea31032e 100644
--- a/src/lib/dhcpsrv/dhcp_parsers.cc
+++ b/src/lib/dhcpsrv/dhcp_parsers.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -400,15 +400,27 @@ void
OptionDataParser::createOption() {
// Option code is held in the uint32_t storage but is supposed to
// be uint16_t value. We need to check that value in the configuration
- // does not exceed range of uint8_t and is not zero.
+ // does not exceed range of uint8_t for DHCPv4, uint16_t for DHCPv6 and
+ // is not zero.
uint32_t option_code = uint32_values_->getParam("code");
if (option_code == 0) {
isc_throw(DhcpConfigError, "option code must not be zero."
- << " Option code '0' is reserved in DHCPv4.");
- } else if (option_code > std::numeric_limits<uint8_t>::max()) {
+ << " Option code '0' is reserved.");
+
+ } else if (global_context_->universe_ == Option::V4 &&
+ option_code > std::numeric_limits<uint8_t>::max()) {
+ isc_throw(DhcpConfigError, "invalid option code '" << option_code
+ << "', it must not exceed '"
+ << static_cast<int>(std::numeric_limits<uint8_t>::max())
+ << "'");
+
+ } else if (global_context_->universe_ == Option::V6 &&
+ option_code > std::numeric_limits<uint16_t>::max()) {
isc_throw(DhcpConfigError, "invalid option code '" << option_code
<< "', it must not exceed '"
- << std::numeric_limits<uint8_t>::max() << "'");
+ << std::numeric_limits<uint16_t>::max()
+ << "'");
+
}
// Check that the option name has been specified, is non-empty and does not
@@ -464,7 +476,7 @@ OptionDataParser::createOption() {
}
// Get option data from the configuration database ('data' field).
- const std::string option_data = string_values_->getParam("data");
+ std::string option_data = string_values_->getParam("data");
// Transform string of hexadecimal digits into binary format.
std::vector<uint8_t> binary;
@@ -480,6 +492,12 @@ OptionDataParser::createOption() {
// Otherwise, the option data is specified as a string of
// hexadecimal digits that we have to turn into binary format.
try {
+ // The decodeHex function expects that the string contains an
+ // even number of digits. If we don't meet this requirement,
+ // we have to insert a leading 0.
+ if (!option_data.empty() && option_data.length() % 2) {
+ option_data = option_data.insert(0, "0");
+ }
util::encode::decodeHex(option_data, binary);
} catch (...) {
isc_throw(DhcpConfigError, "option data is not a valid"
@@ -1163,5 +1181,108 @@ SubnetConfigParser::getParam(const std::string& name) {
return (Triplet<uint32_t>(value));
}
+//**************************** D2ClientConfigParser **********************
+D2ClientConfigParser::D2ClientConfigParser(const std::string& entry_name)
+ : entry_name_(entry_name), boolean_values_(new BooleanStorage()),
+ uint32_values_(new Uint32Storage()), string_values_(new StringStorage()),
+ local_client_config_() {
+}
+
+D2ClientConfigParser::~D2ClientConfigParser() {
+}
+
+void
+D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
+ BOOST_FOREACH(ConfigPair param, client_config->mapValue()) {
+ ParserPtr parser(createConfigParser(param.first));
+ parser->build(param.second);
+ parser->commit();
+ }
+
+ bool enable_updates = boolean_values_->getParam("enable-updates");
+ if (!enable_updates && (client_config->mapValue().size() == 1)) {
+ // If enable-updates is the only parameter and it is false then
+ // we're done. This allows for an abbreviated configuration entry
+ // that only contains that flag. Use the default D2ClientConfig
+ // constructor to a create a disabled instance.
+ local_client_config_.reset(new D2ClientConfig());
+ return;
+ }
+
+ // Get all parameters that are needed to create the D2ClientConfig.
+ asiolink::IOAddress server_ip(string_values_->getParam("server-ip"));
+
+ uint32_t server_port = uint32_values_->getParam("server-port");
+
+ dhcp_ddns::NameChangeProtocol
+ ncr_protocol = dhcp_ddns:: stringToNcrProtocol(string_values_->
+ getParam("ncr-protocol"));
+
+ dhcp_ddns::NameChangeFormat
+ ncr_format = dhcp_ddns::stringToNcrFormat(string_values_->
+ getParam("ncr-format"));
+
+ std::string generated_prefix = string_values_->getParam("generated-prefix");
+ std::string qualifying_suffix = string_values_->
+ getParam("qualifying-suffix");
+
+ bool always_include_fqdn = boolean_values_->getParam("always-include-fqdn");
+ bool override_no_update = boolean_values_->getParam("override-no-update");
+ bool override_client_update = boolean_values_->
+ getParam("override-client-update");
+ bool replace_client_name = boolean_values_->getParam("replace-client-name");
+
+ // Attempt to create the new client config.
+ local_client_config_.reset(new D2ClientConfig(enable_updates, server_ip,
+ server_port, ncr_protocol,
+ ncr_format,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix));
+}
+
+isc::dhcp::ParserPtr
+D2ClientConfigParser::createConfigParser(const std::string& config_id) {
+ DhcpConfigParser* parser = NULL;
+ if (config_id.compare("server-port") == 0) {
+ parser = new Uint32Parser(config_id, uint32_values_);
+ } else if ((config_id.compare("server-ip") == 0) ||
+ (config_id.compare("ncr-protocol") == 0) ||
+ (config_id.compare("ncr-format") == 0) ||
+ (config_id.compare("generated-prefix") == 0) ||
+ (config_id.compare("qualifying-suffix") == 0)) {
+ parser = new StringParser(config_id, string_values_);
+ } else if ((config_id.compare("enable-updates") == 0) ||
+ (config_id.compare("always-include-fqdn") == 0) ||
+ (config_id.compare("allow-client-update") == 0) ||
+ (config_id.compare("override-no-update") == 0) ||
+ (config_id.compare("override-client-update") == 0) ||
+ (config_id.compare("replace-client-name") == 0)) {
+ parser = new BooleanParser(config_id, boolean_values_);
+ } else {
+ isc_throw(NotImplemented,
+ "parser error: D2ClientConfig parameter not supported: "
+ << config_id);
+ }
+
+ return (isc::dhcp::ParserPtr(parser));
+}
+
+void
+D2ClientConfigParser::commit() {
+ // @todo if local_client_config_ is empty then shutdown the listener...
+ // @todo Should this also attempt to start a listener?
+ // In keeping with Interface, Subnet, and Hooks parsers, then this
+ // should initialize the listener. Failure to init it, should cause
+ // rollback. This gets sticky, because who owns the listener instance?
+ // Does CfgMgr maintain it or does the server class? If the latter
+ // how do we get that value here?
+ // I'm thinkikng D2ClientConfig could contain the listener instance
+ CfgMgr::instance().setD2ClientConfig(local_client_config_);
+}
+
}; // namespace dhcp
}; // namespace isc
diff --git a/src/lib/dhcpsrv/dhcp_parsers.h b/src/lib/dhcpsrv/dhcp_parsers.h
index 28c57b8b93..00a07a0a3a 100644
--- a/src/lib/dhcpsrv/dhcp_parsers.h
+++ b/src/lib/dhcpsrv/dhcp_parsers.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -18,6 +18,7 @@
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <dhcp/option_definition.h>
+#include <dhcpsrv/d2_client.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/subnet.h>
@@ -243,7 +244,7 @@ public:
// its value. If it doesn't we insert a new element.
storage_->setParam(param_name_, value_);
}
-
+
private:
/// Pointer to the storage where committed value is stored.
boost::shared_ptr<ValueStorage<ValueType> > storage_;
@@ -876,6 +877,77 @@ protected:
ParserContextPtr global_context_;
};
+/// @brief Parser for D2ClientConfig
+///
+/// This class parses the configuration element "dhcp-ddns" common to the
+/// spec files for both dhcp4 and dhcp6. It creates an instance of a
+/// D2ClientConfig.
+class D2ClientConfigParser : public isc::dhcp::DhcpConfigParser {
+public:
+ /// @brief Constructor
+ ///
+ /// @param entry_name is an arbitrary label assigned to this configuration
+ /// definition.
+ D2ClientConfigParser(const std::string& entry_name);
+
+ /// @brief Destructor
+ virtual ~D2ClientConfigParser();
+
+ /// @brief Performs the parsing of the given dhcp-ddns element.
+ ///
+ /// The results of the parsing are retained internally for use during
+ /// commit.
+ ///
+ /// @param client_config is the "dhcp-ddns" configuration to parse
+ virtual void build(isc::data::ConstElementPtr client_config);
+
+ /// @brief Creates a parser for the given "dhcp-ddns" member element id.
+ ///
+ /// The elements currently supported are (see isc::dhcp::D2ClientConfig
+ /// for details on each):
+ /// -# enable-updates
+ /// -# server-ip
+ /// -# server-port
+ /// -# ncr-protocol
+ /// -# ncr-format
+ /// -# remove-on-renew
+ /// -# always-include-fqdn
+ /// -# allow-client-update
+ /// -# override-no-update
+ /// -# override-client-update
+ /// -# replace-client-name
+ /// -# generated-prefix
+ /// -# qualifying-suffix
+ ///
+ /// @param config_id is the "item_name" for a specific member element of
+ /// the "dns_server" specification.
+ ///
+ /// @return returns a pointer to newly created parser.
+ virtual isc::dhcp::ParserPtr createConfigParser(const std::string&
+ config_id);
+
+ /// @brief Instantiates a D2ClientConfig from internal data values
+ /// passes to CfgMgr singleton.
+ virtual void commit();
+
+private:
+ /// @brief Arbitrary label assigned to this parser instance.
+ /// Primarily used for diagnostics.
+ std::string entry_name_;
+
+ /// Storage for subnet-specific boolean values.
+ BooleanStoragePtr boolean_values_;
+
+ /// Storage for subnet-specific integer values.
+ Uint32StoragePtr uint32_values_;
+
+ /// Storage for subnet-specific string values.
+ StringStoragePtr string_values_;
+
+ /// @brief Pointer to temporary local instance created during build.
+ D2ClientConfigPtr local_client_config_ ;
+};
+
// Pointers to various parser objects.
typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
typedef boost::shared_ptr<StringParser> StringParserPtr;
diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes
index 6ee3e87de7..5c7854e4d1 100644
--- a/src/lib/dhcpsrv/dhcpsrv_messages.mes
+++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes
@@ -70,6 +70,9 @@ specified IPv6 subnet to its database.
A debug message issued when server is being configured to listen on all
interfaces.
+% DHCPSRV_CFGMGR_CFG_DHCP_DDNS Setting DHCP-DDNS configuration to: %1
+A debug message issued when the server's DHCP-DDNS settings are changed.
+
% DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES stop listening on all interfaces
A debug message issued when configuration manager clears the internal list
of active interfaces. This doesn't prevent the server from listening to
diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc
index 4ca6a3ce0b..7bc71f94d8 100644
--- a/src/lib/dhcpsrv/lease.cc
+++ b/src/lib/dhcpsrv/lease.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -56,6 +56,13 @@ bool Lease::expired() const {
return (expire_time < time(NULL));
}
+bool
+Lease::hasIdenticalFqdn(const Lease& other) const {
+ return (hostname_ == other.hostname_ &&
+ fqdn_fwd_ == other.fqdn_fwd_ &&
+ fqdn_rev_ == other.fqdn_rev_);
+}
+
Lease4::Lease4(const Lease4& other)
: Lease(other.addr_, other.t1_, other.t2_, other.valid_lft_,
other.subnet_id_, other.cltt_, other.fqdn_fwd_,
@@ -175,7 +182,7 @@ Lease6::toText() const {
stream << "Type: " << typeToText(type_) << "("
<< static_cast<int>(type_) << ") ";
- stream << "Address: " << addr_.toText() << "\n"
+ stream << "Address: " << addr_ << "\n"
<< "Prefix length: " << static_cast<int>(prefixlen_) << "\n"
<< "IAID: " << iaid_ << "\n"
<< "Pref life: " << preferred_lft_ << "\n"
@@ -190,7 +197,7 @@ std::string
Lease4::toText() const {
ostringstream stream;
- stream << "Address: " << addr_.toText() << "\n"
+ stream << "Address: " << addr_ << "\n"
<< "Valid life: " << valid_lft_ << "\n"
<< "T1: " << t1_ << "\n"
<< "T2: " << t2_ << "\n"
diff --git a/src/lib/dhcpsrv/lease.h b/src/lib/dhcpsrv/lease.h
index 86266205c9..c767142761 100644
--- a/src/lib/dhcpsrv/lease.h
+++ b/src/lib/dhcpsrv/lease.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -141,6 +141,14 @@ struct Lease {
/// @return true if the lease is expired
bool expired() const;
+ /// @brief Returns true if the other lease has equal FQDN data.
+ ///
+ /// @param other Lease which FQDN data is to be compared with our lease.
+ ///
+ /// @return Boolean value which indicates whether FQDN data of the other
+ /// lease is equal to the FQDN data of our lease (true) or not (false).
+ bool hasIdenticalFqdn(const Lease& other) const;
+
};
/// @brief Structure that holds a lease for IPv4 address
diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h
index 9355736de3..aab7b9ed05 100644
--- a/src/lib/dhcpsrv/lease_mgr.h
+++ b/src/lib/dhcpsrv/lease_mgr.h
@@ -214,7 +214,7 @@ public:
/// @param subnet_id A subnet identifier.
///
/// @return A pointer to the lease or NULL if the lease is not found.
- virtual Lease4Ptr getLease4(const ClientId& clientid, const HWAddr& hwaddr,
+ virtual Lease4Ptr getLease4(const ClientId& client_id, const HWAddr& hwaddr,
SubnetID subnet_id) const = 0;
/// @brief Returns existing IPv4 lease for specified client-id
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc
index dbc3bdd5ce..c6c9c9feb1 100644
--- a/src/lib/dhcpsrv/memfile_lease_mgr.cc
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc
@@ -247,7 +247,7 @@ Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
if (lease_it == storage4_.end()) {
isc_throw(NoSuchLease, "failed to update the lease with address "
- << lease->addr_.toText() << " - no such lease");
+ << lease->addr_ << " - no such lease");
}
**lease_it = *lease;
}
@@ -260,7 +260,7 @@ Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
if (lease_it == storage6_.end()) {
isc_throw(NoSuchLease, "failed to update the lease with address "
- << lease->addr_.toText() << " - no such lease");
+ << lease->addr_ << " - no such lease");
}
**lease_it = *lease;
}
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
index 623440bf22..c006bbf5a5 100644
--- a/src/lib/dhcpsrv/mysql_lease_mgr.cc
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -1809,12 +1809,12 @@ MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind,
int affected_rows = mysql_stmt_affected_rows(statements_[stindex]);
if (affected_rows == 0) {
isc_throw(NoSuchLease, "unable to update lease for address " <<
- lease->addr_.toText() << " as it does not exist");
+ lease->addr_ << " as it does not exist");
} else if (affected_rows > 1) {
// Should not happen - primary key constraint should only have selected
// one row.
isc_throw(DbOperationError, "apparently updated more than one lease "
- "that had the address " << lease->addr_.toText());
+ "that had the address " << lease->addr_);
}
}
diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc
index f1ba871aa5..d9c3da0e4d 100644
--- a/src/lib/dhcpsrv/pool.cc
+++ b/src/lib/dhcpsrv/pool.cc
@@ -34,8 +34,8 @@ bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
std::string
Pool::toText() const {
std::stringstream tmp;
- tmp << "type=" << Lease::typeToText(type_) << ", " << first_.toText()
- << "-" << last_.toText();
+ tmp << "type=" << Lease::typeToText(type_) << ", " << first_
+ << "-" << last_;
return (tmp.str());
}
@@ -143,8 +143,8 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
std::string
Pool6::toText() const {
std::stringstream tmp;
- tmp << "type=" << Lease::typeToText(type_) << ", " << first_.toText()
- << "-" << last_.toText() << ", delegated_len="
+ tmp << "type=" << Lease::typeToText(type_) << ", " << first_
+ << "-" << last_ << ", delegated_len="
<< static_cast<int>(prefix_len_);
return (tmp.str());
}
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index d861afe25f..0134d8c9ac 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -24,11 +24,14 @@ using namespace isc::asiolink;
namespace isc {
namespace dhcp {
+// This is an initial value of subnet-id. See comments in subnet.h for details.
+SubnetID Subnet::static_id_ = 1;
+
Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
const Triplet<uint32_t>& t1,
const Triplet<uint32_t>& t2,
const Triplet<uint32_t>& valid_lifetime)
- :id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
+ :id_(generateNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
t2_(t2), valid_(valid_lifetime),
last_allocated_ia_(lastAddrInPrefix(prefix, len)),
last_allocated_ta_(lastAddrInPrefix(prefix, len)),
@@ -162,7 +165,7 @@ void Subnet::setLastAllocated(Lease::Type type,
std::string
Subnet::toText() const {
std::stringstream tmp;
- tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
+ tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
return (tmp.str());
}
@@ -187,7 +190,7 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
if (!siaddr.isV4()) {
isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
- << siaddr.toText());
+ << siaddr);
}
siaddr_ = siaddr;
}
@@ -263,9 +266,8 @@ Subnet::addPool(const PoolPtr& pool) {
IOAddress last_addr = pool->getLastAddress();
if (!inRange(first_addr) || !inRange(last_addr)) {
- isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
- << last_addr.toText()
- << " does not belong in this (" << prefix_.toText() << "/"
+ isc_throw(BadValue, "Pool (" << first_addr << "-" << last_addr
+ << " does not belong in this (" << prefix_ << "/"
<< static_cast<int>(prefix_len_) << ") subnet");
}
@@ -332,7 +334,7 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
:Subnet(prefix, length, t1, t2, valid_lifetime),
preferred_(preferred_lifetime){
if (!prefix.isV6()) {
- isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
+ isc_throw(BadValue, "Non IPv6 prefix " << prefix
<< " specified in subnet6");
}
}
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
index 31dc9477af..ecac6c3af8 100644
--- a/src/lib/dhcpsrv/subnet.h
+++ b/src/lib/dhcpsrv/subnet.h
@@ -366,6 +366,15 @@ public:
/// @return textual representation
virtual std::string toText() const;
+ /// @brief Resets subnet-id counter to its initial value (1)
+ ///
+ /// This should be called during reconfiguration, before any new
+ /// subnet objects are created. It will ensure that the subnet_id will
+ /// be consistent between reconfigures.
+ static void resetSubnetID() {
+ static_id_ = 1;
+ }
+
protected:
/// @brief Returns all pools (non-const variant)
///
@@ -378,7 +387,12 @@ protected:
/// @brief Protected constructor
//
/// By making the constructor protected, we make sure that noone will
- /// ever instantiate that class. Pool4 and Pool6 should be used instead.
+ /// ever instantiate that class. Subnet4 and Subnet6 should be used instead.
+ ///
+ /// This constructor assigns a new subnet-id (see @ref generateNextID).
+ /// This subnet-id has unique value that is strictly monotonously increasing
+ /// for each subnet, until it is explicitly reset back to 1 during
+ /// reconfiguration process.
Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
const Triplet<uint32_t>& t1,
const Triplet<uint32_t>& t2,
@@ -390,12 +404,24 @@ protected:
/// derive from this class.
virtual ~Subnet() { };
+ /// @brief keeps the subnet-id value
+ ///
+ /// It is inreased every time a new Subnet object is created.
+ /// It is reset (@ref resetSubnetId) every time reconfiguration occurs.
+ ///
+ /// Static value initialized in subnet.cc.
+ static SubnetID static_id_;
+
/// @brief returns the next unique Subnet-ID
///
+ /// This method generates and returns the next unique subnet-id.
+ /// It is a strictly monotonously increasing value (1,2,3,...) for
+ /// each new Subnet object created. It can be explicitly reset
+ /// back to 1 during reconfiguration (@ref resetSubnetID).
+ ///
/// @return the next unique Subnet-ID
- static SubnetID getNextID() {
- static SubnetID id = 0;
- return (id++);
+ static SubnetID generateNextID() {
+ return (static_id_++);
}
/// @brief Checks if used pool type is valid
@@ -495,6 +521,8 @@ public:
/// @brief Constructor with all parameters
///
+ /// This constructor calls Subnet::Subnet, where subnet-id is generated.
+ ///
/// @param prefix Subnet4 prefix
/// @param length prefix length
/// @param t1 renewal timer (in seconds)
@@ -559,6 +587,8 @@ public:
/// @brief Constructor with all parameters
///
+ /// This constructor calls Subnet::Subnet, where subnet-id is generated.
+ ///
/// @param prefix Subnet6 prefix
/// @param length prefix length
/// @param t1 renewal timer (in seconds)
diff --git a/src/lib/dhcpsrv/tests/.gitignore b/src/lib/dhcpsrv/tests/.gitignore
index 7add7fb019..33ac8d9e86 100644
--- a/src/lib/dhcpsrv/tests/.gitignore
+++ b/src/lib/dhcpsrv/tests/.gitignore
@@ -1 +1,2 @@
/libdhcpsrv_unittests
+/test_libraries.h
diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am
index 643fd635a2..28f804968c 100644
--- a/src/lib/dhcpsrv/tests/Makefile.am
+++ b/src/lib/dhcpsrv/tests/Makefile.am
@@ -33,7 +33,8 @@ if HAVE_GTEST
# to unexpected errors. For this reason, the --enable-static-link option is
# ignored for unit tests built here.
-lib_LTLIBRARIES = libco1.la libco2.la
+nodistdir=$(abs_top_builddir)/src/lib/dhcpsrv/tests
+nodist_LTLIBRARIES = libco1.la libco2.la
libco1_la_SOURCES = callout_library.cc
libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
@@ -52,6 +53,7 @@ libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc
libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc
libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
@@ -88,6 +90,7 @@ endif
libdhcpsrv_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libb10-dhcp_ddns.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index fda8d59c31..4330efd423 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -94,22 +94,56 @@ public:
duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
iaid_ = 42;
- // instantiate cfg_mgr
+ // Initialize a subnet and short address pool.
+ initSubnet(IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::10"),
+ IOAddress("2001:db8:1::20"));
+
+ initFqdn("", false, false);
+
+ factory_.create("type=memfile");
+ }
+
+ /// @brief Configures a subnet and adds one pool to it.
+ ///
+ /// This function removes existing v6 subnets before configuring
+ /// a new one.
+ ///
+ /// @param subnet Address of a subnet to be configured.
+ /// @param pool_start First address in the address pool.
+ /// @param pool_end Last address in the address pool.
+ void initSubnet(const IOAddress& subnet, const IOAddress& pool_start,
+ const IOAddress& pool_end) {
CfgMgr& cfg_mgr = CfgMgr::instance();
+ cfg_mgr.deleteSubnets6();
+
+ subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
+ pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
- // Configure normal address pool
- subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
- pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::10"),
- IOAddress("2001:db8:1::20")));
subnet_->addPool(pool_);
- // Configure PD pool
- pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 56, 64));
+ pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, subnet, 56, 64));
subnet_->addPool(pd_pool_);
cfg_mgr.addSubnet6(subnet_);
- factory_.create("type=memfile");
+ }
+
+ /// @brief Initializes FQDN data for a test.
+ ///
+ /// The initialized values are used by the test fixture class members to
+ /// verify the correctness of a lease.
+ ///
+ /// @param hostname Hostname to be assigned to a lease.
+ /// @param fqdn_fwd Indicates whether or not to perform forward DNS update
+ /// for a lease.
+ /// @param fqdn_fwd Indicates whether or not to perform reverse DNS update
+ /// for a lease.
+ void initFqdn(const std::string& hostname, const bool fqdn_fwd,
+ const bool fqdn_rev) {
+ hostname_ = hostname;
+ fqdn_fwd_ = fqdn_fwd;
+ fqdn_rev_ = fqdn_rev;
}
/// @brief attempts to convert leases collection to a single lease
@@ -151,10 +185,11 @@ public:
EXPECT_EQ(subnet_->getT1(), lease->t1_);
EXPECT_EQ(subnet_->getT2(), lease->t2_);
EXPECT_EQ(exp_pd_len, lease->prefixlen_);
- EXPECT_TRUE(false == lease->fqdn_fwd_);
- EXPECT_TRUE(false == lease->fqdn_rev_);
+ EXPECT_EQ(fqdn_fwd_, lease->fqdn_fwd_);
+ EXPECT_EQ(fqdn_rev_, lease->fqdn_rev_);
+ EXPECT_EQ(hostname_, lease->hostname_);
EXPECT_TRUE(*lease->duid_ == *duid_);
- // @todo: check cltt
+ /// @todo: check cltt
}
/// @brief Checks if specified address is increased properly
@@ -211,7 +246,7 @@ public:
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, hint, type, false, false,
- "", fake, CalloutHandlePtr())));
+ "", fake, CalloutHandlePtr(), old_leases_)));
// Check that we got a lease
EXPECT_TRUE(lease);
@@ -275,16 +310,16 @@ public:
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, requested, type, false, false, "", false,
- CalloutHandlePtr())));
+ CalloutHandlePtr(), old_leases_)));
// Check that we got a lease
ASSERT_TRUE(lease);
// Allocated address must be different
- EXPECT_NE(used_addr.toText(), lease->addr_.toText());
+ EXPECT_NE(used_addr, lease->addr_);
// We should NOT get what we asked for, because it is used already
- EXPECT_NE(requested.toText(), lease->addr_.toText());
+ EXPECT_NE(requested, lease->addr_);
// Do all checks on the lease
checkLease6(lease, type, expected_pd_len);
@@ -319,13 +354,13 @@ public:
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, hint, type, false,
- false, "", false, CalloutHandlePtr())));
+ false, "", false, CalloutHandlePtr(), old_leases_)));
// Check that we got a lease
ASSERT_TRUE(lease);
// We should NOT get what we asked for, because it is used already
- EXPECT_NE(hint.toText(), lease->addr_.toText());
+ EXPECT_NE(hint, lease->addr_);
// Do all checks on the lease
checkLease6(lease, type, expected_pd_len);
@@ -353,7 +388,14 @@ public:
Subnet6Ptr subnet_; ///< subnet6 (used in tests)
Pool6Ptr pool_; ///< NA pool belonging to subnet_
Pool6Ptr pd_pool_; ///< PD pool belonging to subnet_
+ std::string hostname_; ///< Hostname
+ bool fqdn_fwd_; ///< Perform forward update for a lease.
+ bool fqdn_rev_; ///< Perform reverse update for a lease.
LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
+
+ /// @brief Collection of leases being replaced by newly allocated or renewed
+ /// leases.
+ Lease6Collection old_leases_;
};
/// @brief Used in Allocation Engine tests for IPv4
@@ -408,7 +450,7 @@ public:
EXPECT_TRUE(*lease->client_id_ == *clientid_);
}
EXPECT_TRUE(lease->hwaddr_ == hwaddr_->hwaddr_);
- // @todo: check cltt
+ /// @todo: check cltt
}
virtual ~AllocEngine4Test() {
@@ -476,7 +518,7 @@ TEST_F(AllocEngine6Test, allocWithValidHint6) {
false);
// We should get what we asked for
- EXPECT_EQ(lease->addr_.toText(), "2001:db8:1::15");
+ EXPECT_EQ("2001:db8:1::15", lease->addr_.toText());
}
// This test checks if the address allocation with a hint that is in range,
@@ -521,13 +563,13 @@ TEST_F(AllocEngine6Test, allocateAddress6Nulls) {
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(
Subnet6Ptr(), duid_, iaid_, IOAddress("::"), Lease::TYPE_NA,
- false, false, "", false, CalloutHandlePtr())));
+ false, false, "", false, CalloutHandlePtr(), old_leases_)));
ASSERT_FALSE(lease);
// Allocations without DUID are not allowed either
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
DuidPtr(), iaid_, IOAddress("::"), Lease::TYPE_NA, false,
- false, "", false, CalloutHandlePtr())));
+ false, "", false, CalloutHandlePtr(), old_leases_)));
ASSERT_FALSE(lease);
}
@@ -765,19 +807,18 @@ TEST_F(AllocEngine6Test, smallPool6) {
ASSERT_TRUE(engine);
IOAddress addr("2001:db8:1::ad");
- CfgMgr& cfg_mgr = CfgMgr::instance();
- cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
- // Create configuration similar to other tests, but with a single address pool
- subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
- pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
- subnet_->addPool(pool_);
- cfg_mgr.addSubnet6(subnet_);
+ // Create a subnet with a pool that has one address.
+ initSubnet(IOAddress("2001:db8:1::"), addr, addr);
+
+ // Initialize FQDN for a lease.
+ initFqdn("myhost.example.com", true, true);
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
- duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, false, false,
- "", false, CalloutHandlePtr())));
+ duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, fqdn_fwd_,
+ fqdn_rev_, hostname_, false, CalloutHandlePtr(),
+ old_leases_)));
// Check that we got that single lease
ASSERT_TRUE(lease);
@@ -794,6 +835,11 @@ TEST_F(AllocEngine6Test, smallPool6) {
// Now check that the lease in LeaseMgr has the same parameters
detailCompareLease(lease, from_mgr);
+
+ // This is a new lease allocation. The old lease corresponding to a newly
+ // allocated lease should be NULL.
+ ASSERT_EQ(1, old_leases_.size());
+ EXPECT_FALSE(old_leases_[0]);
}
// This test checks if all addresses in a pool are currently used, the attempt
@@ -826,8 +872,9 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
Lease6Ptr lease2;
EXPECT_NO_THROW(lease2 = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, false, false,
- "", false, CalloutHandlePtr())));
+ "", false, CalloutHandlePtr(), old_leases_)));
EXPECT_FALSE(lease2);
+
}
// This test checks if an expired lease can be reused in SOLICIT (fake allocation)
@@ -837,14 +884,12 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
ASSERT_TRUE(engine);
IOAddress addr("2001:db8:1::ad");
- CfgMgr& cfg_mgr = CfgMgr::instance();
- cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
- // Create configuration similar to other tests, but with a single address pool
- subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
- pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
- subnet_->addPool(pool_);
- cfg_mgr.addSubnet6(subnet_);
+ // Create one subnet with a pool holding one address.
+ initSubnet(IOAddress("2001:db8:1::"), addr, addr);
+
+ // Initialize FQDN data for the lease.
+ initFqdn("myhost.example.com", true, true);
// Just a different duid
DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
@@ -860,11 +905,12 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
// CASE 1: Asking for any address
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
- duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, false, false, "", true,
- CalloutHandlePtr())));
+ duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, fqdn_fwd_,
+ fqdn_rev_, hostname_, true, CalloutHandlePtr(),
+ old_leases_)));
// Check that we got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
// Do all checks on the lease (if subnet-id, preferred/valid times are ok etc.)
checkLease6(lease, Lease::TYPE_NA, 128);
@@ -872,11 +918,11 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
// CASE 2: Asking specifically for this address
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, addr, Lease::TYPE_NA, false, false, "",
- true, CalloutHandlePtr())));
+ true, CalloutHandlePtr(), old_leases_)));
// Check that we got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
}
// This test checks if an expired lease can be reused in REQUEST (actual allocation)
@@ -903,16 +949,32 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
501, 502, 503, 504, other_subnetid, 0));
lease->cltt_ = time(NULL) - 500; // Allocated 500 seconds ago
lease->valid_lft_ = 495; // Lease was valid for 495 seconds
+ lease->fqdn_fwd_ = true;
+ lease->fqdn_rev_ = true;
+ lease->hostname_ = "myhost.example.com.";
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// A client comes along, asking specifically for this address
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, addr, Lease::TYPE_NA, false, false, "",
- false, CalloutHandlePtr())));
+ false, CalloutHandlePtr(), old_leases_)));
// Check that he got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
+ // This reactivated lease should have updated FQDN data.
+ EXPECT_TRUE(lease->hostname_.empty());
+ EXPECT_FALSE(lease->fqdn_fwd_);
+ EXPECT_FALSE(lease->fqdn_rev_);
+
+ // Check that the old lease has been returned.
+ Lease6Ptr old_lease = expectOneLease(old_leases_);
+ // It should at least have the same IPv6 address.
+ EXPECT_EQ(lease->addr_, old_lease->addr_);
+ // Check that it carries not updated FQDN data.
+ EXPECT_EQ("myhost.example.com.", old_lease->hostname_);
+ EXPECT_TRUE(old_lease->fqdn_fwd_);
+ EXPECT_TRUE(old_lease->fqdn_rev_);
// Check that the lease is indeed updated in LeaseMgr
Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
@@ -1075,10 +1137,10 @@ TEST_F(AllocEngine4Test, allocWithUsedHint4) {
ASSERT_TRUE(lease);
// Allocated address must be different
- EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
+ EXPECT_NE(used->addr_, lease->addr_);
// We should NOT get what we asked for, because it is used already
- EXPECT_TRUE(lease->addr_.toText() != "192.0.2.106");
+ EXPECT_NE("192.0.2.106", lease->addr_.toText());
// Do all checks on the lease
checkLease4(lease);
@@ -1115,7 +1177,7 @@ TEST_F(AllocEngine4Test, allocBogusHint4) {
EXPECT_FALSE(old_lease_);
// We should NOT get what we asked for, because it is used already
- EXPECT_TRUE(lease->addr_.toText() != "10.1.1.1");
+ EXPECT_NE("10.1.1.1", lease->addr_.toText());
// Do all checks on the lease
checkLease4(lease);
@@ -1371,7 +1433,7 @@ TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
old_lease_);
// Check that we got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
// We are reusing expired lease, the old (expired) instance should be
// returned. The returned instance should be the same as the original
@@ -1384,13 +1446,13 @@ TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
// CASE 2: Asking specifically for this address
lease = engine->allocateLease4(subnet_, clientid_, hwaddr_,
- IOAddress(addr.toText()),
+ IOAddress(addr),
false, false, "",
true, CalloutHandlePtr(),
old_lease_);
// Check that we got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
// We are updating expired lease. The copy of the old lease should be
// returned and it should be equal to the original lease.
@@ -1425,14 +1487,14 @@ TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
// A client comes along, asking specifically for this address
lease = engine->allocateLease4(subnet_, clientid_, hwaddr_,
- IOAddress(addr.toText()),
+ IOAddress(addr),
false, true, "host.example.com.",
false, CalloutHandlePtr(),
old_lease_);
// Check that he got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
// Check that the lease is indeed updated in LeaseMgr
Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
@@ -1481,7 +1543,7 @@ TEST_F(AllocEngine4Test, renewLease4) {
callout_handle, false);
// Check that he got that single lease
ASSERT_TRUE(lease);
- EXPECT_EQ(addr.toText(), lease->addr_.toText());
+ EXPECT_EQ(addr, lease->addr_);
// Check that the lease matches subnet_, hwaddr_,clientid_ parameters
checkLease4(lease);
@@ -1623,7 +1685,7 @@ TEST_F(HookAllocEngine6Test, lease6_select) {
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, false, false,
- "", false, callout_handle)));
+ "", false, callout_handle, old_leases_)));
// Check that we got a lease
ASSERT_TRUE(lease);
@@ -1694,7 +1756,7 @@ TEST_F(HookAllocEngine6Test, change_lease6_select) {
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(subnet_,
duid_, iaid_, IOAddress("::"), Lease::TYPE_NA, false, false,
- "", false, callout_handle)));
+ "", false, callout_handle, old_leases_)));
// Check that we got a lease
ASSERT_TRUE(lease);
diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
index 08ce768f62..e13cb320aa 100644
--- a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -538,7 +538,7 @@ TEST_F(CfgMgrTest, optionSpace4) {
cfg_mgr.addOptionSpace4(space3), isc::dhcp::InvalidOptionSpace
);
- // @todo decode if a duplicate vendor space is allowed.
+ /// @todo decode if a duplicate vendor space is allowed.
}
// This test verifies that new DHCPv6 option spaces can be added to
@@ -571,7 +571,7 @@ TEST_F(CfgMgrTest, optionSpace6) {
cfg_mgr.addOptionSpace6(space3), isc::dhcp::InvalidOptionSpace
);
- // @todo decide if a duplicate vendor space is allowed.
+ /// @todo decide if a duplicate vendor space is allowed.
}
// This test verifies that it is possible to specify interfaces that server
@@ -670,6 +670,48 @@ TEST_F(CfgMgrTest, echoClientId) {
EXPECT_TRUE(cfg_mgr.echoClientId());
}
+// This test checks the D2ClientMgr wrapper methods.
+TEST_F(CfgMgrTest, d2ClientConfig) {
+ // After CfgMgr construction, D2ClientMgr member should be initialized
+ // with a D2 configuration that is disabled.
+ // Verify we can Fetch the mgr.
+ D2ClientMgr d2_mgr = CfgMgr::instance().getD2ClientMgr();
+ EXPECT_FALSE(d2_mgr.ddnsEnabled());
+
+ // Make sure the convenience method fetches the config correctly.
+ D2ClientConfigPtr original_config = CfgMgr::instance().getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+ EXPECT_FALSE(original_config->getEnableUpdates());
+
+ // Verify that we cannot set the configuration to an empty pointer.
+ D2ClientConfigPtr new_cfg;
+ ASSERT_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg), D2ClientError);
+
+ // Create a new, enabled configuration.
+ ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+
+ // Verify that we can assign a new, non-empty configuration.
+ ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(new_cfg));
+
+ // Verify that we can fetch the newly assigned configuration.
+ D2ClientConfigPtr updated_config = CfgMgr::instance().getD2ClientConfig();
+ ASSERT_TRUE(updated_config);
+ EXPECT_TRUE(updated_config->getEnableUpdates());
+
+ // Make sure convenience method agrees with updated configuration.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+
+ // Make sure the configuration we fetched is the one we assigned,
+ // and not the original configuration.
+ EXPECT_EQ(*new_cfg, *updated_config);
+ EXPECT_NE(*original_config, *updated_config);
+}
+
+
/// @todo Add unit-tests for testing:
/// - addActiveIface() with invalid interface name
/// - addActiveIface() with the same interface twice
diff --git a/src/lib/dhcpsrv/tests/d2_client_unittest.cc b/src/lib/dhcpsrv/tests/d2_client_unittest.cc
new file mode 100644
index 0000000000..8a8550fbe2
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/d2_client_unittest.cc
@@ -0,0 +1,798 @@
+// Copyright (C) 2012-2014 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 <dhcp/option4_client_fqdn.h>
+#include <dhcp/option6_client_fqdn.h>
+#include <dhcpsrv/d2_client.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc;
+
+namespace {
+
+/// @brief Checks constructors and accessors of D2ClientConfig.
+TEST(D2ClientConfigTest, constructorsAndAccessors) {
+ D2ClientConfigPtr d2_client_config;
+
+ // Verify default constructor creates a disabled instance.
+ ASSERT_NO_THROW(d2_client_config.reset(new D2ClientConfig()));
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+ d2_client_config.reset();
+
+ bool enable_updates = true;
+ isc::asiolink::IOAddress server_ip("127.0.0.1");
+ size_t server_port = 477;
+ dhcp_ddns::NameChangeProtocol ncr_protocol = dhcp_ddns::NCR_UDP;
+ dhcp_ddns::NameChangeFormat ncr_format = dhcp_ddns::FMT_JSON;
+ bool always_include_fqdn = true;
+ bool override_no_update = true;
+ bool override_client_update = true;
+ bool replace_client_name = true;
+ std::string generated_prefix = "the_prefix";
+ std::string qualifying_suffix = "the.suffix.";
+
+ // Verify that we can construct a valid, enabled instance.
+ ASSERT_NO_THROW(d2_client_config.reset(new
+ D2ClientConfig(enable_updates,
+ server_ip,
+ server_port,
+ ncr_protocol,
+ ncr_format,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix)));
+
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the accessors return the expected values.
+ EXPECT_EQ(d2_client_config->getEnableUpdates(), enable_updates);
+
+ EXPECT_EQ(d2_client_config->getServerIp(), server_ip);
+ EXPECT_EQ(d2_client_config->getServerPort(), server_port);
+ EXPECT_EQ(d2_client_config->getNcrProtocol(), ncr_protocol);
+ EXPECT_EQ(d2_client_config->getNcrFormat(), ncr_format);
+ EXPECT_EQ(d2_client_config->getAlwaysIncludeFqdn(), always_include_fqdn);
+ EXPECT_EQ(d2_client_config->getOverrideNoUpdate(), override_no_update);
+ EXPECT_EQ(d2_client_config->getOverrideClientUpdate(),
+ override_client_update);
+ EXPECT_EQ(d2_client_config->getReplaceClientName(), replace_client_name);
+ EXPECT_EQ(d2_client_config->getGeneratedPrefix(), generated_prefix);
+ EXPECT_EQ(d2_client_config->getQualifyingSuffix(), qualifying_suffix);
+
+ // Verify that toText called by << operator doesn't bomb.
+ ASSERT_NO_THROW(std::cout << "toText test:" << std::endl <<
+ *d2_client_config << std::endl);
+
+ // Verify that constructor does not allow use of NCR_TCP.
+ /// @todo obviously this becomes invalid once TCP is supported.
+ ASSERT_THROW(d2_client_config.reset(new
+ D2ClientConfig(enable_updates,
+ server_ip,
+ server_port,
+ dhcp_ddns::NCR_TCP,
+ ncr_format,
+ always_include_fqdn,
+ override_no_update,
+ override_client_update,
+ replace_client_name,
+ generated_prefix,
+ qualifying_suffix)),
+ D2ClientError);
+
+ /// @todo if additional validation is added to ctor, this test needs to
+ /// expand accordingly.
+}
+
+/// @brief Tests the equality and inequality operators of D2ClientConfig.
+TEST(D2ClientConfigTest, equalityOperator) {
+ D2ClientConfigPtr ref_config;
+ D2ClientConfigPtr test_config;
+
+ isc::asiolink::IOAddress ref_address("127.0.0.1");
+ isc::asiolink::IOAddress test_address("127.0.0.2");
+
+ // Create an instance to use as a reference.
+ ASSERT_NO_THROW(ref_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(ref_config);
+
+ // Check a configuration that is identical to reference configuration.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_TRUE(*ref_config == *test_config);
+ EXPECT_FALSE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by enable flag.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(false,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by server ip.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ test_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by server port.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 333,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by always_include_fqdn.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, true, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by override_no_update.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, false, true, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by override_client_update.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, false, true,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by replace_client_name.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by generated_prefix.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "bogus", "suf-fix")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+
+ // Check a configuration that differs only by qualifying_suffix.
+ ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+ ref_address, 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "bogus")));
+ ASSERT_TRUE(test_config);
+ EXPECT_FALSE(*ref_config == *test_config);
+ EXPECT_TRUE(*ref_config != *test_config);
+}
+
+/// @brief Checks the D2ClientMgr constructor.
+TEST(D2ClientMgr, constructor) {
+ D2ClientMgrPtr d2_client_mgr;
+
+ // Verify we can construct with the default constructor.
+ ASSERT_NO_THROW(d2_client_mgr.reset(new D2ClientMgr()));
+
+ // After construction, D2 configuration should be disabled.
+ // Fetch it and verify this is the case.
+ D2ClientConfigPtr original_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+ EXPECT_FALSE(original_config->getEnableUpdates());
+
+ // Make sure convenience method agrees.
+ EXPECT_FALSE(d2_client_mgr->ddnsEnabled());
+}
+
+/// @brief Checks passing the D2ClientMgr a valid D2 client configuration.
+/// @todo Once NameChangeSender is integrated, this test needs to expand, and
+/// additional scenario tests will need to be written.
+TEST(D2ClientMgr, validConfig) {
+ D2ClientMgrPtr d2_client_mgr;
+
+ // Construct the manager and fetch its initial configuration.
+ ASSERT_NO_THROW(d2_client_mgr.reset(new D2ClientMgr()));
+ D2ClientConfigPtr original_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(original_config);
+
+ // Verify that we cannot set the config to an empty pointer.
+ D2ClientConfigPtr new_cfg;
+ ASSERT_THROW(d2_client_mgr->setD2ClientConfig(new_cfg), D2ClientError);
+
+ // Create a new, enabled config.
+ ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ true, true, true, true,
+ "pre-fix", "suf-fix")));
+
+ // Verify that we can assign a new, non-empty configuration.
+ ASSERT_NO_THROW(d2_client_mgr->setD2ClientConfig(new_cfg));
+
+ // Verify that we can fetch the newly assigned configuration.
+ D2ClientConfigPtr updated_config = d2_client_mgr->getD2ClientConfig();
+ ASSERT_TRUE(updated_config);
+ EXPECT_TRUE(updated_config->getEnableUpdates());
+
+ // Make sure convenience method agrees with the updated configuration.
+ EXPECT_TRUE(d2_client_mgr->ddnsEnabled());
+
+ // Make sure the configuration we fetched is the one we assigned,
+ // and not the original configuration.
+ EXPECT_EQ(*new_cfg, *updated_config);
+ EXPECT_NE(*original_config, *updated_config);
+}
+
+
+/// @brief Tests that analyzeFqdn detects invalid combination of both the
+/// client S and N flags set to true.
+TEST(D2ClientMgr, analyzeFqdnInvalidCombination) {
+ D2ClientMgr mgr;
+ bool server_s = false;
+ bool server_n = false;
+
+ // Create disabled configuration.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig()));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_FALSE(mgr.ddnsEnabled());
+
+ // client S=1 N=1 is invalid. analyzeFqdn should throw.
+ ASSERT_THROW(mgr.analyzeFqdn(true, true, server_s, server_n),
+ isc::BadValue);
+
+ // Create enabled configuration with all controls off (no overrides).
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+
+ // client S=1 N=1 is invalid. analyzeFqdn should throw.
+ ASSERT_THROW(mgr.analyzeFqdn(true, true, server_s, server_n),
+ isc::BadValue);
+}
+
+/// @brief Tests that analyzeFqdn generates correct server S and N flags when
+/// updates are enabled and all overrides are off.
+TEST(D2ClientMgr, analyzeFqdnEnabledNoOverrides) {
+ D2ClientMgr mgr;
+ bool server_s = false;
+ bool server_n = false;
+
+ // Create enabled configuration with all controls off (no overrides).
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+ ASSERT_FALSE(cfg->getOverrideClientUpdate());
+ ASSERT_FALSE(cfg->getOverrideNoUpdate());
+
+ // client S=0 N=0 means client wants to do forward update.
+ // server S should be 0 (server is not doing forward updates)
+ // and server N should be 1 (server doing no updates)
+ mgr.analyzeFqdn(false, false, server_s, server_n);
+ EXPECT_FALSE(server_s);
+ EXPECT_TRUE(server_n);
+
+ // client S=1 N=0 means client wants server to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ mgr.analyzeFqdn(true, false, server_s, server_n);
+ EXPECT_TRUE(server_s);
+ EXPECT_FALSE(server_n);
+
+
+ // client S=0 N=1 means client wants no one to do forward updates.
+ // server S should be 0 (server is not forward updates)
+ // and server N should be 1 (server is not doing any updates)
+ mgr.analyzeFqdn(false, true, server_s, server_n);
+ EXPECT_FALSE(server_s);
+ EXPECT_TRUE(server_n);
+}
+
+/// @brief Tests that analyzeFqdn generates correct server S and N flags when
+/// updates are enabled and override-no-update is on.
+TEST(D2ClientMgr, analyzeFqdnEnabledOverrideNoUpdate) {
+ D2ClientMgr mgr;
+ bool server_s = false;
+ bool server_n = false;
+
+ // Create enabled configuration with OVERRIDE_NO_UPDATE on.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, true, false, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+ ASSERT_TRUE(cfg->getOverrideNoUpdate());
+ ASSERT_FALSE(cfg->getOverrideClientUpdate());
+
+ // client S=0 N=0 means client wants to do forward update.
+ // server S should be 0 (server is not doing forward updates)
+ // and server N should be 1 (server is not doing any updates)
+ mgr.analyzeFqdn(false, false, server_s, server_n);
+ EXPECT_FALSE(server_s);
+ EXPECT_TRUE(server_n);
+
+ // client S=1 N=0 means client wants server to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ mgr.analyzeFqdn(true, false, server_s, server_n);
+ EXPECT_TRUE(server_s);
+ EXPECT_FALSE(server_n);
+
+ // client S=0 N=1 means client wants no one to do forward updates.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server is doing updates)
+ mgr.analyzeFqdn(false, true, server_s, server_n);
+ EXPECT_TRUE(server_s);
+ EXPECT_FALSE(server_n);
+}
+
+/// @brief Tests that analyzeFqdn generates correct server S and N flags when
+/// updates are enabled and override-client-update is on.
+TEST(D2ClientMgr, analyzeFqdnEnabledOverrideClientUpdate) {
+ D2ClientMgr mgr;
+ bool server_s = false;
+ bool server_n = false;
+
+ // Create enabled configuration with OVERRIDE_CLIENT_UPDATE on.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, true, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+ ASSERT_FALSE(cfg->getOverrideNoUpdate());
+ ASSERT_TRUE(cfg->getOverrideClientUpdate());
+
+ // client S=0 N=0 means client wants to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ mgr.analyzeFqdn(false, false, server_s, server_n);
+ EXPECT_TRUE(server_s);
+ EXPECT_FALSE(server_n);
+
+ // client S=1 N=0 means client wants server to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ mgr.analyzeFqdn(true, false, server_s, server_n);
+ EXPECT_TRUE(server_s);
+ EXPECT_FALSE(server_n);
+
+ // client S=0 N=1 means client wants no one to do forward updates.
+ // server S should be 0 (server is not forward updates)
+ // and server N should be 1 (server is not doing any updates)
+ mgr.analyzeFqdn(false, true, server_s, server_n);
+ EXPECT_FALSE(server_s);
+ EXPECT_TRUE(server_n);
+}
+
+/// @brief Verifies the adustFqdnFlags template with Option4ClientFqdn objects.
+/// Ensures that the method can set the N, S, and O flags properly.
+/// Other permutations are covered by analyzeFqdnFlag tests.
+TEST(D2ClientMgr, adjustFqdnFlagsV4) {
+ D2ClientMgr mgr;
+ Option4ClientFqdnPtr request;
+ Option4ClientFqdnPtr response;
+
+ // Create enabled configuration and override-no-update on.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, true, false, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+ ASSERT_TRUE(cfg->getOverrideNoUpdate());
+ ASSERT_FALSE(cfg->getOverrideClientUpdate());
+
+ // client S=0 N=0 means client wants to do forward update.
+ // server S should be 0 (server is not doing forward updates)
+ // and server N should be 1 (server doing no updates)
+ // and server O should be 0
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option4ClientFqdn>(*request, *response);
+ EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_S));
+ EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_N));
+ EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_O));
+
+ // client S=1 N=0 means client wants server to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ // and server O should be 0
+ request.reset(new Option4ClientFqdn(Option4ClientFqdn::FLAG_S,
+ Option4ClientFqdn::RCODE_CLIENT(),
+ "", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option4ClientFqdn>(*request, *response);
+ EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_S));
+ EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_N));
+ EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_O));
+
+ // client S=0 N=1 means client wants no one to do updates
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ // and O should be 1 (overriding client S)
+ request.reset(new Option4ClientFqdn(Option4ClientFqdn::FLAG_N,
+ Option4ClientFqdn::RCODE_CLIENT(),
+ "", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option4ClientFqdn>(*request, *response);
+ EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_S));
+ EXPECT_FALSE(response->getFlag(Option4ClientFqdn::FLAG_N));
+ EXPECT_TRUE(response->getFlag(Option4ClientFqdn::FLAG_O));
+}
+
+/// @brief Tests the qualifyName method's ability to construct FQDNs
+TEST(D2ClientMgr, qualifyName) {
+ D2ClientMgr mgr;
+
+ // Create enabled configuration.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, true, false,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+
+ // Verify that the qualifying suffix gets appended with trailing dot added.
+ std::string partial_name = "somehost";
+ std::string qualified_name = mgr.qualifyName(partial_name);
+ EXPECT_EQ("somehost.suffix.com.", qualified_name);
+
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, true, false,
+ "prefix", "hasdot.com.")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+
+ // Verify that the qualifying suffix gets appended without dot added.
+ qualified_name = mgr.qualifyName(partial_name);
+ EXPECT_EQ("somehost.hasdot.com.", qualified_name);
+}
+
+
+/// @brief Tests the generateFdqn method's ability to construct FQDNs
+TEST(D2ClientMgr, generateFqdn) {
+ D2ClientMgr mgr;
+
+ // Create enabled configuration.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, true, false,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+
+ // Verify that it works with an IPv4 address.
+ asiolink::IOAddress v4address("192.0.2.75");
+ EXPECT_EQ("prefix-192-0-2-75.suffix.com.", mgr.generateFqdn(v4address));
+
+ // Verify that it works with an IPv6 address.
+ asiolink::IOAddress v6address("2001:db8::2");
+ EXPECT_EQ("prefix-2001-db8--2.suffix.com.", mgr.generateFqdn(v6address));
+
+ // Create a disabled config.
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig()));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+
+ // Verify names generate properly with a disabled configuration.
+ EXPECT_EQ("myhost-192-0-2-75.example.com.", mgr.generateFqdn(v4address));
+ EXPECT_EQ("myhost-2001-db8--2.example.com.", mgr.generateFqdn(v6address));
+}
+
+/// @brief Tests adjustDomainName template method with Option4ClientFqdn
+TEST(D2ClientMgr, adjustDomainNameV4) {
+ D2ClientMgr mgr;
+ Option4ClientFqdnPtr request;
+ Option4ClientFqdnPtr response;
+
+ // Create enabled configuration.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, false,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_FALSE(cfg->getReplaceClientName());
+
+ // replace-client-name is false, client passes in empty fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType());
+
+
+ // replace-client-name is false, client passes in a partial fqdn
+ // response should contain client's name plus the qualifying suffix.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "myhost", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("myhost.suffix.com.", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::FULL, response->getDomainNameType());
+
+
+ // replace-client-name is false, client passes in a full fqdn
+ // response domain should not be altered.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "myhost.example.com.",
+ Option4ClientFqdn::FULL));
+ response.reset(new Option4ClientFqdn(*request));
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("myhost.example.com.", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::FULL, response->getDomainNameType());
+
+ // Create enabled configuration.
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, true,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(cfg->getReplaceClientName());
+
+ // replace-client-name is true, client passes in empty fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType());
+
+ // replace-client-name is true, client passes in a partial fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "myhost", Option4ClientFqdn::PARTIAL));
+ response.reset(new Option4ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType());
+
+
+ // replace-client-name is true, client passes in a full fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option4ClientFqdn(0, Option4ClientFqdn::RCODE_CLIENT(),
+ "myhost.example.com.",
+ Option4ClientFqdn::FULL));
+ response.reset(new Option4ClientFqdn(*request));
+ mgr.adjustDomainName<Option4ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option4ClientFqdn::PARTIAL, response->getDomainNameType());
+}
+
+/// @brief Tests adjustDomainName template method with Option6ClientFqdn
+TEST(D2ClientMgr, adjustDomainNameV6) {
+ D2ClientMgr mgr;
+ Option6ClientFqdnPtr request;
+ Option6ClientFqdnPtr response;
+
+ // Create enabled configuration.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, false,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_FALSE(cfg->getReplaceClientName());
+
+ // replace-client-name is false, client passes in empty fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option6ClientFqdn(0, "", Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType());
+
+ // replace-client-name is false, client passes in a partial fqdn
+ // response should contain client's name plus the qualifying suffix.
+ request.reset(new Option6ClientFqdn(0, "myhost",
+ Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("myhost.suffix.com.", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::FULL, response->getDomainNameType());
+
+
+ // replace-client-name is false, client passes in a full fqdn
+ // response domain should not be altered.
+ request.reset(new Option6ClientFqdn(0, "myhost.example.com.",
+ Option6ClientFqdn::FULL));
+ response.reset(new Option6ClientFqdn(*request));
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("myhost.example.com.", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::FULL, response->getDomainNameType());
+
+ // Create enabled configuration.
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, false, false, true,
+ "prefix", "suffix.com")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(cfg->getReplaceClientName());
+
+ // replace-client-name is true, client passes in empty fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option6ClientFqdn(0, "", Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType());
+
+ // replace-client-name is true, client passes in a partial fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option6ClientFqdn(0, "myhost",
+ Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType());
+
+
+ // replace-client-name is true, client passes in a full fqdn
+ // reponse domain should be empty/partial.
+ request.reset(new Option6ClientFqdn(0, "myhost.example.com.",
+ Option6ClientFqdn::FULL));
+ response.reset(new Option6ClientFqdn(*request));
+ mgr.adjustDomainName<Option6ClientFqdn>(*request, *response);
+ EXPECT_EQ("", response->getDomainName());
+ EXPECT_EQ(Option6ClientFqdn::PARTIAL, response->getDomainNameType());
+}
+
+/// @brief Verifies the adustFqdnFlags template with Option6ClientFqdn objects.
+/// Ensures that the method can set the N, S, and O flags properly.
+/// Other permutations are covered by analyzeFqdnFlags tests.
+TEST(D2ClientMgr, adjustFqdnFlagsV6) {
+ D2ClientMgr mgr;
+ Option6ClientFqdnPtr request;
+ Option6ClientFqdnPtr response;
+
+ // Create enabled configuration and override-no-update on.
+ D2ClientConfigPtr cfg;
+ ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+ isc::asiolink::IOAddress("127.0.0.1"), 477,
+ dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+ false, true, false, false,
+ "pre-fix", "suf-fix")));
+ ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+ ASSERT_TRUE(mgr.ddnsEnabled());
+ ASSERT_TRUE(cfg->getOverrideNoUpdate());
+ ASSERT_FALSE(cfg->getOverrideClientUpdate());
+
+ // client S=0 N=0 means client wants to do forward update.
+ // server S should be 0 (server is not doing forward updates)
+ // and server N should be 1 (server doing no updates)
+ // and server O should be 0
+ request.reset(new Option6ClientFqdn(0, "", Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option6ClientFqdn>(*request, *response);
+ EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_S));
+ EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_N));
+ EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_O));
+
+ // client S=1 N=0 means client wants server to do forward update.
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ // and server O should be 0
+ request.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S,
+ "", Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option6ClientFqdn>(*request, *response);
+ EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_S));
+ EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_N));
+ EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_O));
+
+ // client S=0 N=1 means client wants no one to do updates
+ // server S should be 1 (server is doing forward updates)
+ // and server N should be 0 (server doing updates)
+ // and O should be 1 (overriding client S)
+ request.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_N,
+ "", Option6ClientFqdn::PARTIAL));
+ response.reset(new Option6ClientFqdn(*request));
+ response->resetFlags();
+
+ mgr.adjustFqdnFlags<Option6ClientFqdn>(*request, *response);
+ EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_S));
+ EXPECT_FALSE(response->getFlag(Option6ClientFqdn::FLAG_N));
+ EXPECT_TRUE(response->getFlag(Option6ClientFqdn::FLAG_O));
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
index 928be23ea3..78e3442273 100644
--- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
+++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -367,8 +367,8 @@ public:
///
/// Note that the method currently it only supports option-defs, option-data
/// and hooks-libraries.
- ///
- /// @param config_id is the name of the configuration element.
+ ///
+ /// @param config_id is the name of the configuration element.
///
/// @return returns a shared pointer to DhcpConfigParser.
///
@@ -376,20 +376,21 @@ public:
ParserPtr createConfigParser(const std::string& config_id) {
ParserPtr parser;
if (config_id.compare("option-data") == 0) {
- parser.reset(new OptionDataListParser(config_id,
- parser_context_->options_,
+ parser.reset(new OptionDataListParser(config_id,
+ parser_context_->options_,
parser_context_,
UtestOptionDataParser::factory));
} else if (config_id.compare("option-def") == 0) {
- parser.reset(new OptionDefListParser(config_id,
+ parser.reset(new OptionDefListParser(config_id,
parser_context_->option_defs_));
} else if (config_id.compare("hooks-libraries") == 0) {
parser.reset(new HooksLibrariesParser(config_id));
hooks_libraries_parser_ =
boost::dynamic_pointer_cast<HooksLibrariesParser>(parser);
-
+ } else if (config_id.compare("dhcp-ddns") == 0) {
+ parser.reset(new D2ClientConfigParser(config_id));
} else {
isc_throw(NotImplemented,
"Parser error: configuration parameter not supported: "
@@ -399,8 +400,8 @@ public:
return (parser);
}
- /// @brief Convenience method for parsing a configuration
- ///
+ /// @brief Convenience method for parsing a configuration
+ ///
/// Given a configuration string, convert it into Elements
/// and parse them.
/// @param config is the configuration string to parse
@@ -491,6 +492,10 @@ public:
// Ensure no hooks libraries are loaded.
HooksManager::unloadLibraries();
+
+ // Set it to minimal, disabled config
+ D2ClientConfigPtr tmp(new D2ClientConfig());
+ CfgMgr::instance().setD2ClientConfig(tmp);
}
/// @brief Parsers used in the parsing of the configuration
@@ -566,7 +571,7 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
" \"name\": \"foo\","
" \"space\": \"isc\","
" \"code\": 100,"
- " \"data\": \"192.168.2.1\","
+ " \"data\": \"192.0.2.0\","
" \"csv-format\": True"
" } ]"
"}";
@@ -581,7 +586,7 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
// Verify that the option definition is correct.
std::string val = "type=100, len=4, data fields:\n "
- " #0 192.168.2.1 ( ipv4-address ) \n";
+ " #0 192.0.2.0 ( ipv4-address ) \n";
EXPECT_EQ(val, opt_ptr->toText());
}
@@ -677,7 +682,7 @@ TEST_F(ParseConfigTest, validHooksLibrariesTest) {
// Check with a set of libraries, some of which are invalid.
TEST_F(ParseConfigTest, invalidHooksLibrariesTest) {
- // @todo Initialize global library context to null
+ /// @todo Initialize global library context to null
// Configuration string. This contains an invalid library which should
// trigger an error in the "build" stage.
@@ -703,6 +708,252 @@ TEST_F(ParseConfigTest, invalidHooksLibrariesTest) {
"Error text returned from parse failure is " << error_text_;
}
+/// @brief Checks that a valid, enabled D2 client configuration works correctly.
+TEST_F(ParseConfigTest, validD2Config) {
+
+ // Configuration string containing valid values.
+ std::string config_str =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 3432, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ int rcode = parseConfiguration(config_str);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is enabled and we can fetch the configuration.
+ EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+ D2ClientConfigPtr d2_client_config;
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the configuration values are as expected.
+ EXPECT_TRUE(d2_client_config->getEnableUpdates());
+ EXPECT_EQ("192.0.2.0", d2_client_config->getServerIp().toText());
+ EXPECT_EQ(3432, 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->getAlwaysIncludeFqdn());
+ 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());
+
+ // Another valid Configuration string.
+ // This one is disabled, has IPV6 server ip, control flags false,
+ // empty prefix/suffix
+ std::string config_str2 =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : false, "
+ " \"server-ip\" : \"2001:db8::\", "
+ " \"server-port\" : 43567, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : false, "
+ " \"override-no-update\" : false, "
+ " \"override-client-update\" : false, "
+ " \"replace-client-name\" : false, "
+ " \"generated-prefix\" : \"\", "
+ " \"qualifying-suffix\" : \"\" "
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ rcode = parseConfiguration(config_str2);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is disabled and we can fetch the configuration.
+ EXPECT_FALSE(CfgMgr::instance().ddnsEnabled());
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ ASSERT_TRUE(d2_client_config);
+
+ // Verify that the configuration values are as expected.
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+ EXPECT_EQ("2001:db8::", d2_client_config->getServerIp().toText());
+ EXPECT_EQ(43567, 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_FALSE(d2_client_config->getAlwaysIncludeFqdn());
+ EXPECT_FALSE(d2_client_config->getOverrideNoUpdate());
+ EXPECT_FALSE(d2_client_config->getOverrideClientUpdate());
+ EXPECT_FALSE(d2_client_config->getReplaceClientName());
+ EXPECT_EQ("", d2_client_config->getGeneratedPrefix());
+ EXPECT_EQ("", d2_client_config->getQualifyingSuffix());
+}
+
+/// @brief Checks that D2 client can be configured with enable flag of
+/// false only.
+TEST_F(ParseConfigTest, validDisabledD2Config) {
+
+ // Configuration string. This contains a set of valid libraries.
+ std::string config_str =
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : false"
+ " }"
+ "}";
+
+ // Verify that the configuration string parses.
+ int rcode = parseConfiguration(config_str);
+ ASSERT_TRUE(rcode == 0) << error_text_;
+
+ // Verify that DHCP-DDNS is disabled.
+ EXPECT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+ // Make sure fetched config agrees.
+ D2ClientConfigPtr d2_client_config;
+ ASSERT_NO_THROW(d2_client_config = CfgMgr::instance().getD2ClientConfig());
+ EXPECT_TRUE(d2_client_config);
+ EXPECT_FALSE(d2_client_config->getEnableUpdates());
+}
+
+/// @brief Check various invalid D2 client configurations.
+TEST_F(ParseConfigTest, invalidD2Config) {
+ std::string invalid_configs[] = {
+ // only the enable flag of true
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true"
+ " }"
+ "}",
+ // Missing server ip value
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ //" \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Invalid server ip value
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"x192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unknown protocol
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"Bogus\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unsupported protocol
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"TCP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Unknown format
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"Bogus\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // Missig Port
+ "{ \"dhcp-ddns\" :"
+ " {"
+ " \"enable-updates\" : true, "
+ " \"server-ip\" : \"192.0.2.0\", "
+ // " \"server-port\" : 53001, "
+ " \"ncr-protocol\" : \"UDP\", "
+ " \"ncr-format\" : \"JSON\", "
+ " \"always-include-fqdn\" : true, "
+ " \"override-no-update\" : true, "
+ " \"override-client-update\" : true, "
+ " \"replace-client-name\" : true, "
+ " \"generated-prefix\" : \"test.prefix\", "
+ " \"qualifying-suffix\" : \"test.suffix.\" "
+ " }"
+ "}",
+ // stop
+ ""
+ };
+
+ // Fetch the original config.
+ D2ClientConfigPtr original_config;
+ ASSERT_NO_THROW(original_config = CfgMgr::instance().getD2ClientConfig());
+
+ // Iterate through the invalid configuration strings, attempting to
+ // parse each one. They should fail to parse, but fail gracefully.
+ D2ClientConfigPtr current_config;
+ int i = 0;
+ while (!invalid_configs[i].empty()) {
+ // Verify that the configuration string parses without throwing.
+ int rcode = parseConfiguration(invalid_configs[i]);
+
+ // Verify that parse result indicates a parsing error.
+ ASSERT_TRUE(rcode != 0) << "Invalid config #: " << i
+ << " should not have passed!";
+
+ // Verify that the "official" config still matches the original config.
+ ASSERT_NO_THROW(current_config =
+ CfgMgr::instance().getD2ClientConfig());
+ EXPECT_EQ(*original_config, *current_config);
+ ++i;
+ }
+}
+
/// @brief DHCP Configuration Parser Context test fixture.
class ParserContextTest : public ::testing::Test {
public:
diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
index ab5a8b2162..f8a4aed3b5 100644
--- a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -251,17 +251,6 @@ public:
namespace {
-/// Hardware address used by different tests.
-const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
-/// Client id used by different tests.
-const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
-/// Valid lifetime value used by different tests.
-const uint32_t VALID_LIFETIME = 500;
-/// Subnet ID used by different tests.
-const uint32_t SUBNET_ID = 42;
-/// IAID value used by different tests.
-const uint32_t IAID = 7;
-
/// @brief getParameter test
///
/// This test checks if the LeaseMgr can be instantiated and that it
@@ -320,616 +309,6 @@ TEST_F(LeaseMgrTest, getLease6) {
// are purely virtual, so we would only call ConcreteLeaseMgr methods.
// Those methods are just stubs that do not return anything.
-/// @brief Lease4 Constructor Test
-///
-/// Lease4 is also defined in lease_mgr.h, so is tested in this file as well.
-// This test checks if the Lease4 structure can be instantiated correctly
-TEST(Lease4, constructor) {
-
- // Random values for the tests
- const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
- std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
-
- const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
- std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
- ClientId clientid(clientid_vec);
-
- // ...and a time
- const time_t current_time = time(NULL);
-
- // Other random constants.
- const uint32_t SUBNET_ID = 42;
- const uint32_t VALID_LIFETIME = 500;
-
- // We want to check that various addresses work, so let's iterate over
- // these.
- const uint32_t ADDRESS[] = {
- 0x00000000, 0x01020304, 0x7fffffff, 0x80000000, 0x80000001, 0xffffffff
- };
-
- for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
-
- // Create the lease
- Lease4 lease(ADDRESS[i], HWADDR, sizeof(HWADDR),
- CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0,
- current_time, SUBNET_ID, true, true,
- "hostname.example.com.");
-
- EXPECT_EQ(ADDRESS[i], static_cast<uint32_t>(lease.addr_));
- EXPECT_EQ(0, lease.ext_);
- EXPECT_TRUE(hwaddr == lease.hwaddr_);
- EXPECT_TRUE(clientid == *lease.client_id_);
- EXPECT_EQ(0, lease.t1_);
- EXPECT_EQ(0, lease.t2_);
- EXPECT_EQ(VALID_LIFETIME, lease.valid_lft_);
- EXPECT_EQ(current_time, lease.cltt_);
- EXPECT_EQ(SUBNET_ID, lease.subnet_id_);
- EXPECT_FALSE(lease.fixed_);
- EXPECT_EQ("hostname.example.com.", lease.hostname_);
- EXPECT_TRUE(lease.fqdn_fwd_);
- EXPECT_TRUE(lease.fqdn_rev_);
- EXPECT_TRUE(lease.comments_.empty());
- }
-}
-
-// This test verfies that copy constructor copies Lease4 fields correctly.
-TEST(Lease4, copyConstructor) {
-
- // Random values for the tests
- const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
- std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
-
- const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
- std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
- ClientId clientid(clientid_vec);
-
- // ...and a time
- const time_t current_time = time(NULL);
-
- // Other random constants.
- const uint32_t SUBNET_ID = 42;
- const uint32_t VALID_LIFETIME = 500;
-
- // Create the lease
- Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
- CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
- SUBNET_ID);
-
- // Use copy constructor to copy the lease.
- Lease4 copied_lease(lease);
-
- // Both leases should be now equal. When doing this check we assume that
- // the equality operator works correctly.
- EXPECT_TRUE(lease == copied_lease);
- // Client IDs are equal, but they should be in two distinct pointers.
- EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
-}
-
-// This test verfies that the assignment operator copies all Lease4 fields
-// correctly.
-TEST(Lease4, operatorAssign) {
-
- // Random values for the tests
- const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
- std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
-
- const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
- std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
- ClientId clientid(clientid_vec);
-
- // ...and a time
- const time_t current_time = time(NULL);
-
- // Other random constants.
- const uint32_t SUBNET_ID = 42;
- const uint32_t VALID_LIFETIME = 500;
-
- // Create the lease
- Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
- CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
- SUBNET_ID);
-
- // Use assignment operator to assign the lease.
- Lease4 copied_lease = lease;
-
- // Both leases should be now equal. When doing this check we assume that
- // the equality operator works correctly.
- EXPECT_TRUE(lease == copied_lease);
- // Client IDs are equal, but they should be in two distinct pointers.
- EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
-}
-
-// This test verifies that the matches() returns true if two leases differ
-// by values other than address, HW address, Client ID and ext_.
-TEST(Lease4, matches) {
- // Create two leases which share the same address, HW address, client id
- // and ext_ value.
- const time_t current_time = time(NULL);
- Lease4 lease1(IOAddress("192.0.2.3"), HWADDR, sizeof(HWADDR), CLIENTID,
- sizeof(CLIENTID), VALID_LIFETIME, current_time, 0, 0,
- SUBNET_ID);
- lease1.hostname_ = "lease1.example.com.";
- lease1.fqdn_fwd_ = true;
- lease1.fqdn_rev_ = true;
- Lease4 lease2(IOAddress("192.0.2.3"), HWADDR, sizeof(HWADDR), CLIENTID,
- sizeof(CLIENTID), VALID_LIFETIME + 10, current_time - 10,
- 100, 200, SUBNET_ID);
- lease2.hostname_ = "lease2.example.com.";
- lease2.fqdn_fwd_ = false;
- lease2.fqdn_rev_ = true;
-
- // Leases should match.
- EXPECT_TRUE(lease1.matches(lease2));
- EXPECT_TRUE(lease2.matches(lease1));
-
- // Change address, leases should not match anymore.
- lease1.addr_ = IOAddress("192.0.2.4");
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.addr_ = lease2.addr_;
-
- // Change HW address, leases should not match.
- lease1.hwaddr_[1] += 1;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.hwaddr_ = lease2.hwaddr_;
-
- // Chanage client id, leases should not match.
- std::vector<uint8_t> client_id = lease1.client_id_->getClientId();
- client_id[1] += 1;
- lease1.client_id_.reset(new ClientId(client_id));
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.client_id_ = lease2.client_id_;
-
- // Change ext_, leases should not match.
- lease1.ext_ += 1;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.ext_ = lease2.ext_;
-}
-
-/// @brief Lease4 Equality Test
-///
-/// Checks that the operator==() correctly compares two leases for equality.
-/// As operator!=() is also defined for this class, every check on operator==()
-/// is followed by the reverse check on operator!=().
-TEST(Lease4, operatorEquals) {
-
- // Random values for the tests
- const uint32_t ADDRESS = 0x01020304;
- const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
- std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
- const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
- std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
- ClientId clientid(clientid_vec);
- const time_t current_time = time(NULL);
- const uint32_t SUBNET_ID = 42;
- const uint32_t VALID_LIFETIME = 500;
-
- // Check when the leases are equal.
- Lease4 lease1(ADDRESS, HWADDR, sizeof(HWADDR),
- CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, current_time, 0,
- 0, SUBNET_ID);
- Lease4 lease2(ADDRESS, HWADDR, sizeof(HWADDR),
- CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, current_time, 0, 0,
- SUBNET_ID);
- EXPECT_TRUE(lease1 == lease2);
- EXPECT_FALSE(lease1 != lease2);
-
- // Now vary individual fields in a lease and check that the leases compare
- // not equal in every case.
- lease1.addr_ = IOAddress(ADDRESS + 1);
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.addr_ = lease2.addr_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.ext_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.ext_ = lease2.ext_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.hwaddr_[0];
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.hwaddr_ = lease2.hwaddr_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++clientid_vec[0];
- lease1.client_id_.reset(new ClientId(clientid_vec));
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- --clientid_vec[0];
- lease1.client_id_.reset(new ClientId(clientid_vec));
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.t1_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.t1_ = lease2.t1_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.t2_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.t2_ = lease2.t2_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.valid_lft_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.valid_lft_ = lease2.valid_lft_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.cltt_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.cltt_ = lease2.cltt_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.subnet_id_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.subnet_id_ = lease2.subnet_id_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fixed_ = !lease1.fixed_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fixed_ = lease2.fixed_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.hostname_ += string("Something random");
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.hostname_ = lease2.hostname_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fqdn_fwd_ = !lease1.fqdn_fwd_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fqdn_fwd_ = lease2.fqdn_fwd_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fqdn_rev_ = !lease1.fqdn_rev_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fqdn_rev_ = lease2.fqdn_rev_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.comments_ += string("Something random");
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.comments_ = lease2.comments_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-}
-
-
-
-// Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
-// This test checks if the Lease6 structure can be instantiated correctly
-TEST(Lease6, Lease6ConstructorDefault) {
-
- // check a variety of addresses with different bits set.
- const char* ADDRESS[] = {
- "::", "::1", "2001:db8:1::456",
- "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- "8000::", "8000::1",
- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
- };
-
- // Other values
- uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(llt, sizeof(llt)));
- uint32_t iaid = 7; // Just a number
- SubnetID subnet_id = 8; // Just another number
-
- for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
- IOAddress addr(ADDRESS[i]);
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr,
- duid, iaid, 100, 200, 50, 80,
- subnet_id));
-
- EXPECT_TRUE(lease->addr_ == addr);
- EXPECT_TRUE(*lease->duid_ == *duid);
- EXPECT_TRUE(lease->iaid_ == iaid);
- EXPECT_TRUE(lease->subnet_id_ == subnet_id);
- EXPECT_TRUE(lease->type_ == Lease::TYPE_NA);
- EXPECT_TRUE(lease->preferred_lft_ == 100);
- EXPECT_TRUE(lease->valid_lft_ == 200);
- EXPECT_TRUE(lease->t1_ == 50);
- EXPECT_TRUE(lease->t2_ == 80);
- EXPECT_FALSE(lease->fqdn_fwd_);
- EXPECT_FALSE(lease->fqdn_rev_);
- EXPECT_TRUE(lease->hostname_.empty());
-
- }
-
- // Lease6 must be instantiated with a DUID, not with NULL pointer
- IOAddress addr(ADDRESS[0]);
- Lease6Ptr lease2;
- EXPECT_THROW(lease2.reset(new Lease6(Lease::TYPE_NA, addr,
- DuidPtr(), iaid, 100, 200, 50, 80,
- subnet_id)), InvalidOperation);
-}
-
-// This test verifies that the Lease6 constructor which accepts FQDN data,
-// sets the data correctly for the lease.
-TEST(Lease6, Lease6ConstructorWithFQDN) {
-
- // check a variety of addresses with different bits set.
- const char* ADDRESS[] = {
- "::", "::1", "2001:db8:1::456",
- "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- "8000::", "8000::1",
- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
- };
-
- // Other values
- uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(llt, sizeof(llt)));
- uint32_t iaid = 7; // Just a number
- SubnetID subnet_id = 8; // Just another number
-
- for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
- IOAddress addr(ADDRESS[i]);
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr,
- duid, iaid, 100, 200, 50, 80, subnet_id,
- true, true, "host.example.com."));
-
- EXPECT_TRUE(lease->addr_ == addr);
- EXPECT_TRUE(*lease->duid_ == *duid);
- EXPECT_TRUE(lease->iaid_ == iaid);
- EXPECT_TRUE(lease->subnet_id_ == subnet_id);
- EXPECT_TRUE(lease->type_ == Lease::TYPE_NA);
- EXPECT_TRUE(lease->preferred_lft_ == 100);
- EXPECT_TRUE(lease->valid_lft_ == 200);
- EXPECT_TRUE(lease->t1_ == 50);
- EXPECT_TRUE(lease->t2_ == 80);
- EXPECT_TRUE(lease->fqdn_fwd_);
- EXPECT_TRUE(lease->fqdn_rev_);
- EXPECT_EQ("host.example.com.", lease->hostname_);
- }
- // Lease6 must be instantiated with a DUID, not with NULL pointer
- IOAddress addr(ADDRESS[0]);
- Lease6Ptr lease2;
- EXPECT_THROW(lease2.reset(new Lease6(Lease::TYPE_NA, addr,
- DuidPtr(), iaid, 100, 200, 50, 80,
- subnet_id)), InvalidOperation);
-}
-
-// This test verifies that the matches() function returns true if two leases
-// differ by values other than address, type, prefix length, IAID and DUID.
-TEST(Lease6, matches) {
-
- // Create two matching leases.
- uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(llt, sizeof(llt)));
-
- Lease6 lease1(Lease6::TYPE_NA, IOAddress("2001:db8:1::1"), duid,
- IAID, 100, 200, 50, 80,
- SUBNET_ID);
- lease1.hostname_ = "lease1.example.com.";
- lease1.fqdn_fwd_ = true;
- lease1.fqdn_rev_ = true;
- Lease6 lease2(Lease6::TYPE_NA, IOAddress("2001:db8:1::1"), duid,
- IAID, 200, 300, 90, 70,
- SUBNET_ID);
- lease2.hostname_ = "lease1.example.com.";
- lease2.fqdn_fwd_ = false;
- lease2.fqdn_rev_ = true;
-
- EXPECT_TRUE(lease1.matches(lease2));
-
- // Modify each value used to match both leases, and make sure that
- // leases don't match.
-
- // Modify address.
- lease1.addr_ = IOAddress("2001:db8:1::2");
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.addr_ = lease2.addr_;
-
- // Modify lease type.
- lease1.type_ = Lease6::TYPE_TA;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.type_ = lease2.type_;
-
- // Modify prefix length.
- lease1.prefixlen_ += 1;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.prefixlen_ = lease2.prefixlen_;
-
- // Modify IAID.
- lease1.iaid_ += 1;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.iaid_ = lease2.iaid_;
-
- // Modify DUID.
- llt[1] += 1;
- duid.reset(new DUID(llt, sizeof(llt)));
- lease1.duid_ = duid;
- EXPECT_FALSE(lease1.matches(lease2));
- lease1.duid_ = lease2.duid_;
-}
-
-/// @brief Lease6 Equality Test
-///
-/// Checks that the operator==() correctly compares two leases for equality.
-/// As operator!=() is also defined for this class, every check on operator==()
-/// is followed by the reverse check on operator!=().
-TEST(Lease6, OperatorEquals) {
-
- // check a variety of addresses with different bits set.
- const IOAddress addr("2001:db8:1::456");
- uint8_t duid_array[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(duid_array, sizeof(duid_array)));
- uint32_t iaid = 7; // just a number
- SubnetID subnet_id = 8; // just another number
-
- // Check for equality.
- Lease6 lease1(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
- subnet_id);
- Lease6 lease2(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
- subnet_id);
-
- // cltt_ constructs with time(NULL), make sure they are always equal
- lease1.cltt_ = lease2.cltt_;
-
- EXPECT_TRUE(lease1 == lease2);
- EXPECT_FALSE(lease1 != lease2);
-
- // Go through and alter all the fields one by one
-
- lease1.addr_ = IOAddress("::1");
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.addr_ = lease2.addr_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.type_ = Lease::TYPE_PD;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.type_ = lease2.type_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.prefixlen_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.prefixlen_ = lease2.prefixlen_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.iaid_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.iaid_ = lease2.iaid_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++duid_array[0];
- lease1.duid_.reset(new DUID(duid_array, sizeof(duid_array)));
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- --duid_array[0];
- lease1.duid_.reset(new DUID(duid_array, sizeof(duid_array)));
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.preferred_lft_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.preferred_lft_ = lease2.preferred_lft_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.valid_lft_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.valid_lft_ = lease2.valid_lft_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.t1_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.t1_ = lease2.t1_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.t2_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.t2_ = lease2.t2_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.cltt_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.cltt_ = lease2.cltt_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- ++lease1.subnet_id_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.subnet_id_ = lease2.subnet_id_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fixed_ = !lease1.fixed_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fixed_ = lease2.fixed_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.hostname_ += string("Something random");
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.hostname_ = lease2.hostname_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fqdn_fwd_ = !lease1.fqdn_fwd_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fqdn_fwd_ = lease2.fqdn_fwd_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.fqdn_rev_ = !lease1.fqdn_rev_;
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.fqdn_rev_ = lease2.fqdn_rev_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-
- lease1.comments_ += string("Something random");
- EXPECT_FALSE(lease1 == lease2);
- EXPECT_TRUE(lease1 != lease2);
- lease1.comments_ = lease2.comments_;
- EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
- EXPECT_FALSE(lease1 != lease2); // ... leases equal
-}
-
-// Checks if lease expiration is calculated properly
-TEST(Lease6, Lease6Expired) {
- const IOAddress addr("2001:db8:1::456");
- const uint8_t duid_array[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- const DuidPtr duid(new DUID(duid_array, sizeof(duid_array)));
- const uint32_t iaid = 7; // Just a number
- const SubnetID subnet_id = 8; // Just another number
- Lease6 lease(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
- subnet_id);
-
- // Case 1: a second before expiration
- lease.cltt_ = time(NULL) - 100;
- lease.valid_lft_ = 101;
- EXPECT_FALSE(lease.expired());
-
- // Case 2: the lease will expire after this second is concluded
- lease.cltt_ = time(NULL) - 101;
- EXPECT_FALSE(lease.expired());
-
- // Case 3: the lease is expired
- lease.cltt_ = time(NULL) - 102;
- EXPECT_TRUE(lease.expired());
-}
}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/lease_unittest.cc b/src/lib/dhcpsrv/tests/lease_unittest.cc
index 6f57f30e39..4e7451f2d1 100644
--- a/src/lib/dhcpsrv/tests/lease_unittest.cc
+++ b/src/lib/dhcpsrv/tests/lease_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 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
@@ -13,23 +13,342 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <dhcpsrv/lease.h>
#include <gtest/gtest.h>
#include <vector>
using namespace isc;
+using namespace isc::asiolink;
using namespace isc::dhcp;
namespace {
-// @todo Currently this file contains tests for new functions which return DUID
-// or client identifier. Other tests for Lease objects must be implemented.
-// See http://bind10.isc.org/ticket/3240.
+/// Hardware address used by different tests.
+const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+/// Client id used by different tests.
+const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+/// Valid lifetime value used by different tests.
+const uint32_t VALID_LIFETIME = 500;
+/// Subnet ID used by different tests.
+const uint32_t SUBNET_ID = 42;
+/// IAID value used by different tests.
+const uint32_t IAID = 7;
+
+/// @brief Creates an instance of the lease with certain FQDN data.
+///
+/// @param hostname Hostname.
+/// @param fqdn_fwd Forward FQDN update setting for a created lease.
+/// @param fqdn_rev Reverse FQDN update setting for a created lease.
+///
+/// @return Instance of the created lease.
+Lease4 createLease4(const std::string& hostname, const bool fqdn_fwd,
+ const bool fqdn_rev) {
+ Lease4 lease;
+ lease.hostname_ = hostname;
+ lease.fqdn_fwd_ = fqdn_fwd;
+ lease.fqdn_rev_ = fqdn_rev;
+ return (lease);
+}
+
+/// Lease4 is also defined in lease_mgr.h, so is tested in this file as well.
+// This test checks if the Lease4 structure can be instantiated correctly
+TEST(Lease4, constructor) {
+
+ // Random values for the tests
+ const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+ std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+
+ const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+ std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+ ClientId clientid(clientid_vec);
+
+ // ...and a time
+ const time_t current_time = time(NULL);
+
+ // Other random constants.
+ const uint32_t SUBNET_ID = 42;
+ const uint32_t VALID_LIFETIME = 500;
+
+ // We want to check that various addresses work, so let's iterate over
+ // these.
+ const uint32_t ADDRESS[] = {
+ 0x00000000, 0x01020304, 0x7fffffff, 0x80000000, 0x80000001, 0xffffffff
+ };
+
+ for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
+
+ // Create the lease
+ Lease4 lease(ADDRESS[i], HWADDR, sizeof(HWADDR),
+ CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0,
+ current_time, SUBNET_ID, true, true,
+ "hostname.example.com.");
+
+ EXPECT_EQ(ADDRESS[i], static_cast<uint32_t>(lease.addr_));
+ EXPECT_EQ(0, lease.ext_);
+ EXPECT_TRUE(hwaddr == lease.hwaddr_);
+ EXPECT_TRUE(clientid == *lease.client_id_);
+ EXPECT_EQ(0, lease.t1_);
+ EXPECT_EQ(0, lease.t2_);
+ EXPECT_EQ(VALID_LIFETIME, lease.valid_lft_);
+ EXPECT_EQ(current_time, lease.cltt_);
+ EXPECT_EQ(SUBNET_ID, lease.subnet_id_);
+ EXPECT_FALSE(lease.fixed_);
+ EXPECT_EQ("hostname.example.com.", lease.hostname_);
+ EXPECT_TRUE(lease.fqdn_fwd_);
+ EXPECT_TRUE(lease.fqdn_rev_);
+ EXPECT_TRUE(lease.comments_.empty());
+ }
+}
+
+// This test verfies that copy constructor copies Lease4 fields correctly.
+TEST(Lease4, copyConstructor) {
+
+ // Random values for the tests
+ const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+ std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+
+ const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+ std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+ ClientId clientid(clientid_vec);
+
+ // ...and a time
+ const time_t current_time = time(NULL);
+
+ // Other random constants.
+ const uint32_t SUBNET_ID = 42;
+ const uint32_t VALID_LIFETIME = 500;
+
+ // Create the lease
+ Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
+ CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
+ SUBNET_ID);
+
+ // Use copy constructor to copy the lease.
+ Lease4 copied_lease(lease);
+
+ // Both leases should be now equal. When doing this check we assume that
+ // the equality operator works correctly.
+ EXPECT_TRUE(lease == copied_lease);
+ // Client IDs are equal, but they should be in two distinct pointers.
+ EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+}
+
+// This test verfies that the assignment operator copies all Lease4 fields
+// correctly.
+TEST(Lease4, operatorAssign) {
+
+ // Random values for the tests
+ const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+ std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+
+ const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+ std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+ ClientId clientid(clientid_vec);
+
+ // ...and a time
+ const time_t current_time = time(NULL);
+
+ // Other random constants.
+ const uint32_t SUBNET_ID = 42;
+ const uint32_t VALID_LIFETIME = 500;
+
+ // Create the lease
+ Lease4 lease(0xffffffff, HWADDR, sizeof(HWADDR),
+ CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
+ SUBNET_ID);
+
+ // Use assignment operator to assign the lease.
+ Lease4 copied_lease = lease;
+
+ // Both leases should be now equal. When doing this check we assume that
+ // the equality operator works correctly.
+ EXPECT_TRUE(lease == copied_lease);
+ // Client IDs are equal, but they should be in two distinct pointers.
+ EXPECT_FALSE(lease.client_id_ == copied_lease.client_id_);
+}
+
+// This test verifies that the matches() returns true if two leases differ
+// by values other than address, HW address, Client ID and ext_.
+TEST(Lease4, matches) {
+ // Create two leases which share the same address, HW address, client id
+ // and ext_ value.
+ const time_t current_time = time(NULL);
+ Lease4 lease1(IOAddress("192.0.2.3"), HWADDR, sizeof(HWADDR), CLIENTID,
+ sizeof(CLIENTID), VALID_LIFETIME, current_time, 0, 0,
+ SUBNET_ID);
+ lease1.hostname_ = "lease1.example.com.";
+ lease1.fqdn_fwd_ = true;
+ lease1.fqdn_rev_ = true;
+ Lease4 lease2(IOAddress("192.0.2.3"), HWADDR, sizeof(HWADDR), CLIENTID,
+ sizeof(CLIENTID), VALID_LIFETIME + 10, current_time - 10,
+ 100, 200, SUBNET_ID);
+ lease2.hostname_ = "lease2.example.com.";
+ lease2.fqdn_fwd_ = false;
+ lease2.fqdn_rev_ = true;
+
+ // Leases should match.
+ EXPECT_TRUE(lease1.matches(lease2));
+ EXPECT_TRUE(lease2.matches(lease1));
+
+ // Change address, leases should not match anymore.
+ lease1.addr_ = IOAddress("192.0.2.4");
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.addr_ = lease2.addr_;
+
+ // Change HW address, leases should not match.
+ lease1.hwaddr_[1] += 1;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.hwaddr_ = lease2.hwaddr_;
+
+ // Chanage client id, leases should not match.
+ std::vector<uint8_t> client_id = lease1.client_id_->getClientId();
+ client_id[1] += 1;
+ lease1.client_id_.reset(new ClientId(client_id));
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.client_id_ = lease2.client_id_;
+
+ // Change ext_, leases should not match.
+ lease1.ext_ += 1;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.ext_ = lease2.ext_;
+}
+
+/// @brief Lease4 Equality Test
+///
+/// Checks that the operator==() correctly compares two leases for equality.
+/// As operator!=() is also defined for this class, every check on operator==()
+/// is followed by the reverse check on operator!=().
+TEST(Lease4, operatorEquals) {
+
+ // Random values for the tests
+ const uint32_t ADDRESS = 0x01020304;
+ const uint8_t HWADDR[] = {0x08, 0x00, 0x2b, 0x02, 0x3f, 0x4e};
+ std::vector<uint8_t> hwaddr(HWADDR, HWADDR + sizeof(HWADDR));
+ const uint8_t CLIENTID[] = {0x17, 0x34, 0xe2, 0xff, 0x09, 0x92, 0x54};
+ std::vector<uint8_t> clientid_vec(CLIENTID, CLIENTID + sizeof(CLIENTID));
+ ClientId clientid(clientid_vec);
+ const time_t current_time = time(NULL);
+ const uint32_t SUBNET_ID = 42;
+ const uint32_t VALID_LIFETIME = 500;
+
+ // Check when the leases are equal.
+ Lease4 lease1(ADDRESS, HWADDR, sizeof(HWADDR),
+ CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, current_time, 0,
+ 0, SUBNET_ID);
+ Lease4 lease2(ADDRESS, HWADDR, sizeof(HWADDR),
+ CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, current_time, 0, 0,
+ SUBNET_ID);
+ EXPECT_TRUE(lease1 == lease2);
+ EXPECT_FALSE(lease1 != lease2);
+
+ // Now vary individual fields in a lease and check that the leases compare
+ // not equal in every case.
+ lease1.addr_ = IOAddress(ADDRESS + 1);
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.addr_ = lease2.addr_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.ext_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.ext_ = lease2.ext_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.hwaddr_[0];
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.hwaddr_ = lease2.hwaddr_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++clientid_vec[0];
+ lease1.client_id_.reset(new ClientId(clientid_vec));
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ --clientid_vec[0];
+ lease1.client_id_.reset(new ClientId(clientid_vec));
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.t1_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.t1_ = lease2.t1_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.t2_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.t2_ = lease2.t2_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.valid_lft_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.valid_lft_ = lease2.valid_lft_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.cltt_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.cltt_ = lease2.cltt_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.subnet_id_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.subnet_id_ = lease2.subnet_id_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fixed_ = !lease1.fixed_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fixed_ = lease2.fixed_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.hostname_ += std::string("Something random");
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.hostname_ = lease2.hostname_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fqdn_fwd_ = !lease1.fqdn_fwd_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fqdn_fwd_ = lease2.fqdn_fwd_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fqdn_rev_ = !lease1.fqdn_rev_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fqdn_rev_ = lease2.fqdn_rev_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.comments_ += std::string("Something random");
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.comments_ = lease2.comments_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+}
// Verify that the client id can be returned as a vector object and if client
// id is NULL the empty vector is returned.
-TEST(Lease4Test, getClientIdVector) {
+TEST(Lease4, getClientIdVector) {
// Create a lease.
Lease4 lease;
// By default, the lease should have client id set to NULL. If it doesn't,
@@ -47,9 +366,356 @@ TEST(Lease4Test, getClientIdVector) {
EXPECT_TRUE(returned_vec == client_id_vec);
}
+// Verify the behavior of the function which checks FQDN data for equality.
+TEST(Lease4, hasIdenticalFqdn) {
+ Lease4 lease = createLease4("myhost.example.com.", true, true);
+ EXPECT_TRUE(lease.hasIdenticalFqdn(createLease4("myhost.example.com.",
+ true, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease4("other.example.com.",
+ true, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease4("myhost.example.com.",
+ false, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease4("myhost.example.com.",
+ true, false)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease4("myhost.example.com.",
+ false, false)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease4("other.example.com.",
+ false, false)));
+}
+
+/// @brief Creates an instance of the lease with certain FQDN data.
+///
+/// @param hostname Hostname.
+/// @param fqdn_fwd Forward FQDN update setting for a created lease.
+/// @param fqdn_rev Reverse FQDN update setting for a created lease.
+///
+/// @return Instance of the created lease.
+Lease6 createLease6(const std::string& hostname, const bool fqdn_fwd,
+ const bool fqdn_rev) {
+ Lease6 lease;
+ lease.hostname_ = hostname;
+ lease.fqdn_fwd_ = fqdn_fwd;
+ lease.fqdn_rev_ = fqdn_rev;
+ return (lease);
+}
+
+// Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
+// This test checks if the Lease6 structure can be instantiated correctly
+TEST(Lease6, Lease6ConstructorDefault) {
+
+ // check a variety of addresses with different bits set.
+ const char* ADDRESS[] = {
+ "::", "::1", "2001:db8:1::456",
+ "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ "8000::", "8000::1",
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
+ };
+
+ // Other values
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(llt, sizeof(llt)));
+ uint32_t iaid = 7; // Just a number
+ SubnetID subnet_id = 8; // Just another number
+
+ for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
+ IOAddress addr(ADDRESS[i]);
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr,
+ duid, iaid, 100, 200, 50, 80,
+ subnet_id));
+
+ EXPECT_TRUE(lease->addr_ == addr);
+ EXPECT_TRUE(*lease->duid_ == *duid);
+ EXPECT_TRUE(lease->iaid_ == iaid);
+ EXPECT_TRUE(lease->subnet_id_ == subnet_id);
+ EXPECT_TRUE(lease->type_ == Lease::TYPE_NA);
+ EXPECT_TRUE(lease->preferred_lft_ == 100);
+ EXPECT_TRUE(lease->valid_lft_ == 200);
+ EXPECT_TRUE(lease->t1_ == 50);
+ EXPECT_TRUE(lease->t2_ == 80);
+ EXPECT_FALSE(lease->fqdn_fwd_);
+ EXPECT_FALSE(lease->fqdn_rev_);
+ EXPECT_TRUE(lease->hostname_.empty());
+
+ }
+
+ // Lease6 must be instantiated with a DUID, not with NULL pointer
+ IOAddress addr(ADDRESS[0]);
+ Lease6Ptr lease2;
+ EXPECT_THROW(lease2.reset(new Lease6(Lease::TYPE_NA, addr,
+ DuidPtr(), iaid, 100, 200, 50, 80,
+ subnet_id)), InvalidOperation);
+}
+
+// This test verifies that the Lease6 constructor which accepts FQDN data,
+// sets the data correctly for the lease.
+TEST(Lease6, Lease6ConstructorWithFQDN) {
+
+ // check a variety of addresses with different bits set.
+ const char* ADDRESS[] = {
+ "::", "::1", "2001:db8:1::456",
+ "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ "8000::", "8000::1",
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
+ };
+
+ // Other values
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(llt, sizeof(llt)));
+ uint32_t iaid = 7; // Just a number
+ SubnetID subnet_id = 8; // Just another number
+
+ for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
+ IOAddress addr(ADDRESS[i]);
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr,
+ duid, iaid, 100, 200, 50, 80, subnet_id,
+ true, true, "host.example.com."));
+
+ EXPECT_TRUE(lease->addr_ == addr);
+ EXPECT_TRUE(*lease->duid_ == *duid);
+ EXPECT_TRUE(lease->iaid_ == iaid);
+ EXPECT_TRUE(lease->subnet_id_ == subnet_id);
+ EXPECT_TRUE(lease->type_ == Lease::TYPE_NA);
+ EXPECT_TRUE(lease->preferred_lft_ == 100);
+ EXPECT_TRUE(lease->valid_lft_ == 200);
+ EXPECT_TRUE(lease->t1_ == 50);
+ EXPECT_TRUE(lease->t2_ == 80);
+ EXPECT_TRUE(lease->fqdn_fwd_);
+ EXPECT_TRUE(lease->fqdn_rev_);
+ EXPECT_EQ("host.example.com.", lease->hostname_);
+ }
+
+ // Lease6 must be instantiated with a DUID, not with NULL pointer
+ IOAddress addr(ADDRESS[0]);
+ Lease6Ptr lease2;
+ EXPECT_THROW(lease2.reset(new Lease6(Lease::TYPE_NA, addr,
+ DuidPtr(), iaid, 100, 200, 50, 80,
+ subnet_id)), InvalidOperation);
+}
+
+// This test verifies that the matches() function returns true if two leases
+// differ by values other than address, type, prefix length, IAID and DUID.
+TEST(Lease6, matches) {
+
+ // Create two matching leases.
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+ Lease6 lease1(Lease6::TYPE_NA, IOAddress("2001:db8:1::1"), duid,
+ IAID, 100, 200, 50, 80,
+ SUBNET_ID);
+ lease1.hostname_ = "lease1.example.com.";
+ lease1.fqdn_fwd_ = true;
+ lease1.fqdn_rev_ = true;
+ Lease6 lease2(Lease6::TYPE_NA, IOAddress("2001:db8:1::1"), duid,
+ IAID, 200, 300, 90, 70,
+ SUBNET_ID);
+ lease2.hostname_ = "lease1.example.com.";
+ lease2.fqdn_fwd_ = false;
+ lease2.fqdn_rev_ = true;
+
+ EXPECT_TRUE(lease1.matches(lease2));
+
+ // Modify each value used to match both leases, and make sure that
+ // leases don't match.
+
+ // Modify address.
+ lease1.addr_ = IOAddress("2001:db8:1::2");
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.addr_ = lease2.addr_;
+
+ // Modify lease type.
+ lease1.type_ = Lease6::TYPE_TA;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.type_ = lease2.type_;
+
+ // Modify prefix length.
+ lease1.prefixlen_ += 1;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.prefixlen_ = lease2.prefixlen_;
+
+ // Modify IAID.
+ lease1.iaid_ += 1;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.iaid_ = lease2.iaid_;
+
+ // Modify DUID.
+ llt[1] += 1;
+ duid.reset(new DUID(llt, sizeof(llt)));
+ lease1.duid_ = duid;
+ EXPECT_FALSE(lease1.matches(lease2));
+ lease1.duid_ = lease2.duid_;
+}
+
+/// @brief Lease6 Equality Test
+///
+/// Checks that the operator==() correctly compares two leases for equality.
+/// As operator!=() is also defined for this class, every check on operator==()
+/// is followed by the reverse check on operator!=().
+TEST(Lease6, OperatorEquals) {
+
+ // check a variety of addresses with different bits set.
+ const IOAddress addr("2001:db8:1::456");
+ uint8_t duid_array[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(duid_array, sizeof(duid_array)));
+ uint32_t iaid = 7; // just a number
+ SubnetID subnet_id = 8; // just another number
+
+ // Check for equality.
+ Lease6 lease1(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
+ subnet_id);
+ Lease6 lease2(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
+ subnet_id);
+
+ // cltt_ constructs with time(NULL), make sure they are always equal
+ lease1.cltt_ = lease2.cltt_;
+
+ EXPECT_TRUE(lease1 == lease2);
+ EXPECT_FALSE(lease1 != lease2);
+
+ // Go through and alter all the fields one by one
+
+ lease1.addr_ = IOAddress("::1");
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.addr_ = lease2.addr_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.type_ = Lease::TYPE_PD;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.type_ = lease2.type_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.prefixlen_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.prefixlen_ = lease2.prefixlen_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.iaid_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.iaid_ = lease2.iaid_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++duid_array[0];
+ lease1.duid_.reset(new DUID(duid_array, sizeof(duid_array)));
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ --duid_array[0];
+ lease1.duid_.reset(new DUID(duid_array, sizeof(duid_array)));
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.preferred_lft_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.preferred_lft_ = lease2.preferred_lft_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.valid_lft_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.valid_lft_ = lease2.valid_lft_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.t1_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.t1_ = lease2.t1_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.t2_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.t2_ = lease2.t2_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.cltt_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.cltt_ = lease2.cltt_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ ++lease1.subnet_id_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.subnet_id_ = lease2.subnet_id_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fixed_ = !lease1.fixed_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fixed_ = lease2.fixed_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.hostname_ += std::string("Something random");
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.hostname_ = lease2.hostname_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fqdn_fwd_ = !lease1.fqdn_fwd_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fqdn_fwd_ = lease2.fqdn_fwd_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.fqdn_rev_ = !lease1.fqdn_rev_;
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.fqdn_rev_ = lease2.fqdn_rev_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+
+ lease1.comments_ += std::string("Something random");
+ EXPECT_FALSE(lease1 == lease2);
+ EXPECT_TRUE(lease1 != lease2);
+ lease1.comments_ = lease2.comments_;
+ EXPECT_TRUE(lease1 == lease2); // Check that the reversion has made the
+ EXPECT_FALSE(lease1 != lease2); // ... leases equal
+}
+
+// Checks if lease expiration is calculated properly
+TEST(Lease6, Lease6Expired) {
+ const IOAddress addr("2001:db8:1::456");
+ const uint8_t duid_array[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ const DuidPtr duid(new DUID(duid_array, sizeof(duid_array)));
+ const uint32_t iaid = 7; // Just a number
+ const SubnetID subnet_id = 8; // Just another number
+ Lease6 lease(Lease::TYPE_NA, addr, duid, iaid, 100, 200, 50, 80,
+ subnet_id);
+
+ // Case 1: a second before expiration
+ lease.cltt_ = time(NULL) - 100;
+ lease.valid_lft_ = 101;
+ EXPECT_FALSE(lease.expired());
+
+ // Case 2: the lease will expire after this second is concluded
+ lease.cltt_ = time(NULL) - 101;
+ EXPECT_FALSE(lease.expired());
+
+ // Case 3: the lease is expired
+ lease.cltt_ = time(NULL) - 102;
+ EXPECT_TRUE(lease.expired());
+}
+
// Verify that the DUID can be returned as a vector object and if DUID is NULL
// the empty vector is returned.
-TEST(Lease6Test, getDuidVector) {
+TEST(Lease6, getDuidVector) {
// Create a lease.
Lease6 lease;
// By default, the lease should have client id set to NULL. If it doesn't,
@@ -67,5 +733,21 @@ TEST(Lease6Test, getDuidVector) {
EXPECT_TRUE(returned_vec == duid_vec);
}
+// Verify the behavior of the function which checks FQDN data for equality.
+TEST(Lease6, hasIdenticalFqdn) {
+ Lease6 lease = createLease6("myhost.example.com.", true, true);
+ EXPECT_TRUE(lease.hasIdenticalFqdn(createLease6("myhost.example.com.",
+ true, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease6("other.example.com.",
+ true, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease6("myhost.example.com.",
+ false, true)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease6("myhost.example.com.",
+ true, false)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease6("myhost.example.com.",
+ false, false)));
+ EXPECT_FALSE(lease.hasIdenticalFqdn(createLease6("other.example.com.",
+ false, false)));
+}
}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
index 85015f623d..657075001f 100644
--- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -95,7 +95,7 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
IOAddress("2001:db8:1::456"));
ASSERT_TRUE(x);
- EXPECT_EQ(x->addr_.toText(), addr.toText());
+ EXPECT_EQ(x->addr_, addr);
EXPECT_TRUE(*x->duid_ == *duid);
EXPECT_EQ(x->iaid_, iaid);
EXPECT_EQ(x->subnet_id_, subnet_id);
@@ -114,7 +114,7 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
ASSERT_TRUE(y);
EXPECT_TRUE(*y->duid_ == *duid);
EXPECT_EQ(y->iaid_, iaid);
- EXPECT_EQ(y->addr_.toText(), addr.toText());
+ EXPECT_EQ(y->addr_, addr);
// Test getLease6(duid, iaid, subnet_id) - wrong iaid
uint32_t invalid_iaid = 9; // no such iaid
@@ -144,7 +144,7 @@ TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
EXPECT_EQ(Lease6Ptr(), x);
}
-// @todo Write more memfile tests
+/// @todo Write more memfile tests
// Simple test about lease4 retrieval through client id method
TEST_F(MemfileLeaseMgrTest, getLease4ClientId) {
diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
index d5e00ab1ea..578ef3c089 100644
--- a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
+++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2014 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
@@ -549,7 +549,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4Hwaddr) {
}
// Get the leases matching the hardware address of lease 1
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
HWAddr tmp(leases[1]->hwaddr_, HTYPE_ETHER);
Lease4Collection returned = lmptr_->getLease4(tmp);
@@ -568,14 +568,14 @@ TEST_F(MySqlLeaseMgrTest, getLease4Hwaddr) {
EXPECT_EQ(straddress4_[5], addresses[2]);
// Repeat test with just one expected match
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[2]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[2], *returned.begin());
// Check that an empty vector is valid
EXPECT_TRUE(leases[7]->hwaddr_.empty());
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[7]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[7], *returned.begin());
@@ -599,7 +599,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSize) {
for (uint8_t i = 0; i <= HWAddr::MAX_HWADDR_LEN; ++i) {
leases[1]->hwaddr_.resize(i, i);
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Collection returned =
lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, HTYPE_ETHER));
@@ -610,7 +610,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSize) {
// Database should not let us add one that is too big
// (The 42 is a random value put in each byte of the address.)
- // @todo: 2589 will make this test impossible
+ /// @todo: 2589 will make this test impossible
leases[1]->hwaddr_.resize(HWAddr::MAX_HWADDR_LEN + 100, 42);
EXPECT_THROW(lmptr_->addLease(leases[1]), isc::dhcp::DbOperationError);
}
@@ -628,7 +628,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Get the leases matching the hardware address of lease 1 and
// subnet ID of lease 1. Result should be a single lease - lease 1.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER), leases[1]->subnet_id_);
@@ -637,7 +637,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Try for a match to the hardware address of lease 1 and the wrong
// subnet ID.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, HTYPE_ETHER),
leases[1]->subnet_id_ + 1);
EXPECT_FALSE(returned);
@@ -645,14 +645,14 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
// Try for a match to the subnet ID of lease 1 (and lease 4) but
// the wrong hardware address.
vector<uint8_t> invalid_hwaddr(15, 0x77);
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(invalid_hwaddr, HTYPE_ETHER),
leases[1]->subnet_id_);
EXPECT_FALSE(returned);
// Try for a match to an unknown hardware address and an unknown
// subnet ID.
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(invalid_hwaddr, HTYPE_ETHER),
leases[1]->subnet_id_ + 1);
EXPECT_FALSE(returned);
@@ -665,7 +665,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
EXPECT_TRUE(lmptr_->deleteLease(leases[2]->addr_));
leases[1]->addr_ = leases[2]->addr_;
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
EXPECT_THROW(returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER),
leases[1]->subnet_id_),
@@ -687,7 +687,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetIdSize) {
for (uint8_t i = 0; i <= HWAddr::MAX_HWADDR_LEN; ++i) {
leases[1]->hwaddr_.resize(i, i);
EXPECT_TRUE(lmptr_->addLease(leases[1]));
- // @todo: Simply use HWAddr directly once 2589 is implemented
+ /// @todo: Simply use HWAddr directly once 2589 is implemented
Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
HTYPE_ETHER),
leases[1]->subnet_id_);
diff --git a/src/lib/dhcpsrv/tests/test_utils.cc b/src/lib/dhcpsrv/tests/test_utils.cc
index e418c6208d..44d60ea4ff 100644
--- a/src/lib/dhcpsrv/tests/test_utils.cc
+++ b/src/lib/dhcpsrv/tests/test_utils.cc
@@ -48,7 +48,7 @@ detailCompareLease(const Lease4Ptr& first, const Lease4Ptr& second) {
// odd things happen when they are different: the EXPECT_EQ macro appears to
// call the operator uint32_t() function, which causes an exception to be
// thrown for IPv6 addresses.
- EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
+ EXPECT_EQ(first->addr_, second->addr_);
EXPECT_TRUE(first->hwaddr_ == second->hwaddr_);
if (first->client_id_ && second->client_id_) {
EXPECT_TRUE(*first->client_id_ == *second->client_id_);
@@ -83,7 +83,7 @@ detailCompareLease(const Lease6Ptr& first, const Lease6Ptr& second) {
// odd things happen when they are different: the EXPECT_EQ macro appears to
// call the operator uint32_t() function, which causes an exception to be
// thrown for IPv6 addresses.
- EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
+ EXPECT_EQ(first->addr_, second->addr_);
EXPECT_EQ(first->prefixlen_, second->prefixlen_);
EXPECT_EQ(first->iaid_, second->iaid_);
ASSERT_TRUE(first->duid_);