BIND 10 trac3036, updated. 87e43d5dfdb2b3c470e6f3c81e786b49a9a621c5 [3036] Generate NameChangeRequests for Solicit, Request, Renew and Release.
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jul 26 15:39:59 UTC 2013
The branch, trac3036 has been updated
via 87e43d5dfdb2b3c470e6f3c81e786b49a9a621c5 (commit)
via b74b04e1944680e73163cb8f229111d7be3df2c3 (commit)
from 3e90051aa1a97eb1c450ba223ef2659220e97a45 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 87e43d5dfdb2b3c470e6f3c81e786b49a9a621c5
Author: Marcin Siodelski <marcin at isc.org>
Date: Fri Jul 26 17:39:14 2013 +0200
[3036] Generate NameChangeRequests for Solicit, Request, Renew and Release.
commit b74b04e1944680e73163cb8f229111d7be3df2c3
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Jul 23 21:53:45 2013 +0200
[3036] Added function which creates an on-wire format of the domain-name.
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp6/Makefile.am | 5 +
src/bin/dhcp6/dhcp6_messages.mes | 12 +
src/bin/dhcp6/dhcp6_srv.cc | 311 ++++++++++++--
src/bin/dhcp6/dhcp6_srv.h | 100 +++--
src/bin/dhcp6/tests/Makefile.am | 5 +
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 541 ++++++++++++++++++++++--
src/lib/dhcp/option6_client_fqdn.cc | 28 +-
src/lib/dhcp/option6_client_fqdn.h | 7 +
src/lib/dhcp/option6_ia.h | 9 +-
src/lib/dhcp/option6_iaaddr.h | 6 +
src/lib/dhcpsrv/alloc_engine.cc | 33 +-
src/lib/dhcpsrv/alloc_engine.h | 26 +-
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc | 33 +-
13 files changed, 978 insertions(+), 138 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 3b07510..6f2c694 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -54,6 +54,11 @@ b10_dhcp6_SOURCES += config_parser.cc config_parser.h
b10_dhcp6_SOURCES += dhcp6_log.cc dhcp6_log.h
b10_dhcp6_SOURCES += dhcp6_srv.cc dhcp6_srv.h
+# Temporarily compile this file here. It will be removed once libdhcp-ddns
+# is implemented which will include this file and other files required
+# by DHCPv6.
+b10_dhcp6_SOURCES += ../d2/ncr_msg.cc ../d2/ncr_msg.h
+
nodist_b10_dhcp6_SOURCES = dhcp6_messages.h dhcp6_messages.cc
EXTRA_DIST += dhcp6_messages.mes
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 6b61473..91fea72 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -65,6 +65,18 @@ This informational message is printed every time the IPv6 DHCP server
is started. It indicates what database backend type is being to store
lease and other information.
+% DHCP6_DDNS_REMOVE_EMPTY_HOSTNAME FQDN for the lease being deleted is empty: %1
+This error message is issued when a lease being deleted contains an indication
+that the DNS Update has been performed for it, but the FQDN is missing for this
+lease. This is an indication that someone may have messed up in the lease
+database.
+
+% DHCP6_DDNS_REMOVE_INVALID_HOSTNAME FQDN for the lease being deleted has invalid format: %1
+This error message is issued when a lease being deleted contains an indication
+that the DNS Update has been performed for it, but the FQDN held in the lease
+database has invalid format and can't be transformed to the canonical on-wire
+format.
+
% DHCP6_LEASE_ADVERT lease %1 advertised (client duid=%2, iaid=%3)
This debug message indicates that the server successfully advertised
a lease. It is up to the client to choose one server out of the
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 30e6d01..879cade 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -15,6 +15,7 @@
#include <config.h>
#include <asiolink/io_address.h>
+#include <d2/ncr_msg.h>
#include <dhcp/dhcp6.h>
#include <dhcp/duid.h>
#include <dhcp/iface_mgr.h>
@@ -198,15 +199,15 @@ bool Dhcpv6Srv::run() {
break;
case DHCPV6_REQUEST:
- rsp = processRequest(query, ncr);
+ rsp = processRequest(query);
break;
case DHCPV6_RENEW:
- rsp = processRenew(query, ncr);
+ rsp = processRenew(query);
break;
case DHCPV6_REBIND:
- rsp = processRebind(query, ncr);
+ rsp = processRebind(query);
break;
case DHCPV6_CONFIRM:
@@ -214,7 +215,7 @@ bool Dhcpv6Srv::run() {
break;
case DHCPV6_RELEASE:
- rsp = processRelease(query, ncr);
+ rsp = processRelease(query);
break;
case DHCPV6_DECLINE:
@@ -596,7 +597,8 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
}
void
-Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& fqdn) {
// We need to allocate addresses for all IA_NA options in the client's
// question (i.e. SOLICIT or REQUEST) message.
@@ -651,7 +653,9 @@ Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
switch (opt->second->getType()) {
case D6O_IA_NA: {
OptionPtr answer_opt = assignIA_NA(subnet, duid, question,
- boost::dynamic_pointer_cast<Option6IA>(opt->second));
+ boost::dynamic_pointer_cast<
+ Option6IA>(opt->second),
+ fqdn);
if (answer_opt) {
answer->addOption(answer_opt);
}
@@ -663,15 +667,14 @@ Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
}
-void
-Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, Pkt6Ptr& answer,
- NameChangeRequestPtr& ncr) {
+Option6ClientFqdnPtr
+Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question) {
// Get Client FQDN Option from the client's message. If this option hasn't
// been included, do nothing.
Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
Option6ClientFqdn>(question->getOption(D6O_CLIENT_FQDN));
if (!fqdn) {
- return;
+ return (fqdn);
}
// Prepare the FQDN option which will be included in the response to
@@ -688,9 +691,10 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, Pkt6Ptr& answer,
// server neither respects delegation of updates nor it is configured
// to send update on its own when client requested delegation.
if (!FQDN_ENABLE_UPDATE ||
- (fqdn->getFlag(Option6ClientFqdn::FLAG_N) && !FQDN_OVERRIDE_NO_UPDATE) ||
- (!fqdn->getFlag(Option6ClientFqdn::FLAG_S) && !FQDN_ALLOW_CLIENT_UPDATE &&
- !FQDN_OVERRIDE_CLIENT_UPDATE)) {
+ (fqdn->getFlag(Option6ClientFqdn::FLAG_N) &&
+ !FQDN_OVERRIDE_NO_UPDATE) ||
+ (!fqdn->getFlag(Option6ClientFqdn::FLAG_S) &&
+ !FQDN_ALLOW_CLIENT_UPDATE && !FQDN_OVERRIDE_CLIENT_UPDATE)) {
fqdn_resp->setFlag(Option6ClientFqdn::FLAG_N, true);
// Conditions when S flag is set to indicate that server will perform
@@ -734,6 +738,24 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, Pkt6Ptr& answer,
}
+ // Return the FQDN option which can be included in the server's response.
+ // Note that it doesn't have to be included, if client didn't request
+ // it using ORO and server is not configured to always include it.
+ return (fqdn_resp);
+}
+
+
+void
+Dhcpv6Srv::appendClientFqdn(const Pkt6Ptr& question,
+ Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& fqdn) {
+
+ // If FQDN is NULL, it means that client did not request DNS Update, plus
+ // server doesn't force updates.
+ if (fqdn) {
+ return;
+ }
+
// Server sends back the FQDN option to the client if client has requested
// it using Option Request Option. However, server may be configured to
// send the FQDN option in its response, regardless whether client requested
@@ -753,23 +775,137 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, Pkt6Ptr& answer,
}
if (include_fqdn) {
- answer->addOption(fqdn_resp);
+ answer->addOption(fqdn);
+ }
+
+}
+
+void
+Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& opt_fqdn) {
+
+ // It is likely that client haven't included the FQDN option in the message
+ // and server is not configured to always update DNS. In such cases,
+ // FQDN option will be NULL. This is valid state, so we simply return.
+ if (!opt_fqdn) {
+ return;
+ }
+
+ // The response message instance is always required. For instance it
+ // holds the Client Identifier. It is a programming error if supplied
+ // message is NULL.
+ if (!answer) {
+ isc_throw(isc::Unexpected, "an instance of the object"
+ << " encapsulating server's message must not be"
+ << " NULL when creating DNS NameChangeRequest");
}
- createNameChangeRequest(answer, fqdn_resp, ncr);
+ // Get the Client Id. It is mandatory and a function creating a response
+ // would have thrown an exception if it was missing. Thus throwning
+ // Unexpected if it is missing as it is a programming error.
+ OptionPtr opt_duid = answer->getOption(D6O_CLIENTID);
+ if (!opt_duid) {
+ isc_throw(isc::Unexpected,
+ "client identifier is required when creating a new"
+ " DNS NameChangeRequest");
+ }
+ DuidPtr duid = DuidPtr(new DUID(opt_duid->getData()));
+
+ // Get the FQDN in the on-wire format. It will be needed to compute
+ // DHCID.
+ OutputBuffer name_buf(1);
+ opt_fqdn->packDomainName(name_buf);
+ const uint8_t* name_data = static_cast<const uint8_t*>(name_buf.getData());
+ // @todo currently D2Dhcid accepts a vector holding FQDN.
+ // However, it will be faster if we used a pointer name_data.
+ std::vector<uint8_t> buf_vec(name_data, name_data + name_buf.getLength());
+ // Compute DHCID from Client Identifier and FQDN.
+ isc::d2::D2Dhcid dhcid(*duid, buf_vec);
+
+ // Get all IAs from the answer. For each IA, holding an address we will
+ // create a corresponding NameChangeRequest.
+ Option::OptionCollection answer_ias = answer->getOptions(D6O_IA_NA);
+ for (Option::OptionCollection::const_iterator answer_ia =
+ answer_ias.begin(); answer_ia != answer_ias.end(); ++answer_ia) {
+ Option6IAAddrPtr iaaddr = boost::static_pointer_cast<
+ Option6IAAddr>(answer_ia->second->getOption(D6O_IAADDR));
+ // We need an address to create a name-to-address mapping.
+ // If address is missing for any reason, go to the next IA.
+ if (!iaaddr) {
+ continue;
+ }
+ // Create new NameChangeRequest. Use the domain name from the FQDN.
+ // This is an FQDN included in the response to the client, so it
+ // holds a fully qualified domain-name already (not partial).
+ // Get the IP address from the lease. Also, use the S flag to determine
+ // if forward change should be performed. This flag will always be
+ // set if server has taken responsibility for the forward update.
+ NameChangeRequest ncr(isc::d2::CHG_ADD,
+ opt_fqdn->getFlag(Option6ClientFqdn::FLAG_S),
+ true, opt_fqdn->getDomainName(),
+ iaaddr->getAddress().toText(),
+ dhcid, 0, iaaddr->getValid());
+ // Add the request to the queue. This queue will be read elsewhere in
+ // the code and all requests from this queue will be sent to the
+ // D2 module.
+ name_change_reqs_.push(ncr);
+ }
}
void
-Dhcpv6Srv::createNameChangeRequest(const Pkt6Ptr&,
- const Option6ClientFqdnPtr&,
- isc::d2::NameChangeRequestPtr&) {
- // @todo Create NameChangeRequest here.
+Dhcpv6Srv::createRemovalNameChangeRequest(const Lease6Ptr& lease) {
+ // If we haven't performed a DNS Update when lease was acquired,
+ // there is nothing to do here.
+ if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
+ return;
+ }
+
+ // When lease was added into a database the host name should have
+ // been added. The hostname can be empty if someone messed up in the
+ // lease data base and removed the hostname.
+ if (lease->hostname_.empty()) {
+ LOG_ERROR(dhcp6_logger, DHCP6_DDNS_REMOVE_EMPTY_HOSTNAME)
+ .arg(lease->addr_.toText());
+ return;
+ }
+
+ // If hostname is non-empty, try to convert it to wire format so as
+ // DHCID can be computed from it. This may throw an exception if hostname
+ // has invalid format. Again, this should be only possible in case of
+ // manual intervention in the database.
+ std::vector<uint8_t> hostname_wire;
+ try {
+ OptionDataTypeUtil::writeFqdn(lease->hostname_, hostname_wire);
+ } catch (const Exception& ex) {
+ LOG_ERROR(dhcp6_logger, DHCP6_DDNS_REMOVE_INVALID_HOSTNAME);
+ return;
+ }
+
+ // DUID must have been checked already by the caller of this function.
+ // Let's be on the safe side and make sure it is non-NULL and throw
+ // an exception if it is NULL.
+ if (!lease->duid_) {
+ isc_throw(isc::Unexpected, "DUID must be set when creating"
+ << " NameChangeRequest for DNS records removal for "
+ << lease->addr_.toText());
+
+ }
+ isc::d2::D2Dhcid dhcid(*lease->duid_, hostname_wire);
+
+ // Create a NameChangeRequest to remove the entry.
+ NameChangeRequest ncr(isc::d2::CHG_REMOVE,
+ lease->fqdn_fwd_, lease->fqdn_rev_,
+ lease->hostname_,
+ lease->addr_.toText(),
+ dhcid, 0, lease->valid_lft_);
+ name_change_reqs_.push(ncr);
}
OptionPtr
Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
- Pkt6Ptr question, boost::shared_ptr<Option6IA> ia) {
+ Pkt6Ptr question, Option6IAPtr ia,
+ const Option6ClientFqdnPtr& fqdn) {
// If there is no subnet selected for handling this IA_NA, the only thing to do left is
// to say that we are sorry, but the user won't get an address. As a convenience, we
// use a different status text to indicate that (compare to the same status code,
@@ -813,12 +949,41 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
fake_allocation = true;
}
+ // At this point, we have to make make some decisions with respect to the
+ // FQDN option that we have generated as a result of receiving client's
+ // FQDN. In particular, we have to get to know if the DNS update will be
+ // performed or not. It is possible that option is NULL, which is valid
+ // condition if client didn't request DNS updates and server didn't force
+ // the update.
+ bool do_fwd = false;
+ bool do_rev = false;
+ if (fqdn) {
+ // Flag S must not coexist with flag N being set to 1, so if S=1
+ // server takes responsibility for both reverse and forward updates.
+ // Otherwise, we have to check N.
+ if (fqdn->getFlag(Option6ClientFqdn::FLAG_S)) {
+ do_fwd = true;
+ do_rev = true;
+ } else if (!fqdn->getFlag(Option6ClientFqdn::FLAG_N)) {
+ do_rev = true;
+ }
+ }
+ // Set hostname only in case any of the updates is being performed.
+ std::string hostname;
+ if (do_fwd || do_rev) {
+ hostname = fqdn->getDomainName();
+ }
+
// Use allocation engine to pick a lease for this client. Allocation engine
// will try to honour the hint, but it is just a hint - some other address
// may be used instead. If fake_allocation is set to false, the lease will
// be inserted into the LeaseMgr as well.
- Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid, ia->getIAID(),
- hint, fake_allocation);
+ Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid,
+ ia->getIAID(),
+ hint,
+ do_fwd, do_rev,
+ hostname,
+ fake_allocation);
// Create IA_NA that we will put in the response.
// Do not use OptionDefinition to create option's instance so
@@ -847,6 +1012,22 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
// It would be possible to insert status code=0(success) as well,
// but this is considered waste of bandwidth as absence of status
// code is considered a success.
+
+ // Allocation engine may have returned an existing lease. If so, we
+ // have to check that the FQDN settings we provided are the same
+ // that were set. If they aren't, we will have to remove existing
+ // DNS records and update the lease with the new settings.
+ if ((lease->hostname_ != hostname) || (lease->fqdn_fwd_ != do_fwd) ||
+ (lease->fqdn_rev_ != do_rev)) {
+ // Schedule removal of the existing lease.
+ createRemovalNameChangeRequest(lease);
+ // Set the new lease properties and update.
+ lease->hostname_ = hostname;
+ lease->fqdn_fwd_ = do_fwd;
+ lease->fqdn_rev_ = do_rev;
+ LeaseMgrFactory::instance().updateLease6(lease);
+ }
+
} else {
// Allocation engine did not allocate a lease. The engine logged
// cause of that failure. The only thing left is to insert
@@ -865,7 +1046,8 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
OptionPtr
Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
- Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia) {
+ Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia,
+ const Option6ClientFqdnPtr& fqdn) {
if (!subnet) {
// There's no subnet select for this client. There's nothing to renew.
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
@@ -902,11 +1084,43 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
return (ia_rsp);
}
+ // At this point, we have to make make some decisions with respect to the
+ // FQDN option that we have generated as a result of receiving client's
+ // FQDN. In particular, we have to get to know if the DNS update will be
+ // performed or not. It is possible that option is NULL, which is valid
+ // condition if client didn't request DNS updates and server didn't force
+ // the update.
+ bool do_fwd = false;
+ bool do_rev = false;
+ if (fqdn) {
+ if (fqdn->getFlag(Option6ClientFqdn::FLAG_S)) {
+ do_fwd = true;
+ do_rev = true;
+ } else if (!fqdn->getFlag(Option6ClientFqdn::FLAG_N)) {
+ do_rev = true;
+ }
+ }
+
+ std::string hostname;
+ if (do_fwd || do_rev) {
+ hostname = fqdn->getDomainName();
+ }
+
+ // If the new FQDN settings have changed for the lease, we need to
+ // delete any existing FQDN records for this lease.
+ if ((lease->hostname_ != hostname) || (lease->fqdn_fwd_ != do_fwd) ||
+ (lease->fqdn_rev_ != do_rev)) {
+ createRemovalNameChangeRequest(lease);
+ }
+
lease->preferred_lft_ = subnet->getPreferred();
lease->valid_lft_ = subnet->getValid();
lease->t1_ = subnet->getT1();
lease->t2_ = subnet->getT2();
lease->cltt_ = time(NULL);
+ lease->hostname_ = hostname;
+ lease->fqdn_fwd_ = do_fwd;
+ lease->fqdn_rev_ = do_rev;
LeaseMgrFactory::instance().updateLease6(lease);
@@ -924,7 +1138,8 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
}
void
-Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
+Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply,
+ const Option6ClientFqdnPtr& fqdn) {
// We need to renew addresses for all IA_NA options in the client's
// RENEW message.
@@ -968,7 +1183,9 @@ Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
switch (opt->second->getType()) {
case D6O_IA_NA: {
OptionPtr answer_opt = renewIA_NA(subnet, duid, renew,
- boost::dynamic_pointer_cast<Option6IA>(opt->second));
+ boost::dynamic_pointer_cast<
+ Option6IA>(opt->second),
+ fqdn);
if (answer_opt) {
reply->addOption(answer_opt);
}
@@ -1144,6 +1361,11 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
ia_rsp->addOption(createStatusCode(STATUS_Success,
"Lease released. Thank you, please come again."));
+ // Check if a lease has flags indicating that the FQDN update has
+ // been performed. If so, create NameChangeRequest which removes
+ // the entries.
+ createRemovalNameChangeRequest(lease);
+
return (ia_rsp);
}
}
@@ -1159,17 +1381,18 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
appendDefaultOptions(solicit, advertise);
appendRequestedOptions(solicit, advertise);
- assignLeases(solicit, advertise);
-
- NameChangeRequestPtr ncr;
- processClientFqdn(solicit, advertise, ncr);
+ Option6ClientFqdnPtr fqdn = processClientFqdn(solicit);
+ assignLeases(solicit, advertise, fqdn);
+ appendClientFqdn(solicit, advertise, fqdn);
+ // Note, that we don't create NameChangeRequests here because we don't
+ // perform DNS Updates for Solicit. Client must send Request to update
+ // DNS.
return (advertise);
}
Pkt6Ptr
-Dhcpv6Srv::processRequest(const Pkt6Ptr& request,
- NameChangeRequestPtr& ncr) {
+Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
sanityCheck(request, MANDATORY, MANDATORY);
@@ -1179,16 +1402,16 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request,
appendDefaultOptions(request, reply);
appendRequestedOptions(request, reply);
- assignLeases(request, reply);
-
- processClientFqdn(request, reply, ncr);
+ Option6ClientFqdnPtr fqdn = processClientFqdn(request);
+ assignLeases(request, reply, fqdn);
+ appendClientFqdn(request, reply, fqdn);
+ createNameChangeRequests(reply, fqdn);
return (reply);
}
Pkt6Ptr
-Dhcpv6Srv::processRenew(const Pkt6Ptr& renew,
- NameChangeRequestPtr& ncr) {
+Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
sanityCheck(renew, MANDATORY, MANDATORY);
@@ -1198,16 +1421,17 @@ Dhcpv6Srv::processRenew(const Pkt6Ptr& renew,
appendDefaultOptions(renew, reply);
appendRequestedOptions(renew, reply);
- processClientFqdn(renew, reply, ncr);
-
- renewLeases(renew, reply);
+ Option6ClientFqdnPtr fqdn = processClientFqdn(renew);
+ renewLeases(renew, reply, fqdn);
+ appendClientFqdn(renew, reply, fqdn);
+ createNameChangeRequests(reply, fqdn);
return reply;
}
Pkt6Ptr
-Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind,
- NameChangeRequestPtr&) {
+Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+
/// @todo: Implement this
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
return reply;
@@ -1221,8 +1445,7 @@ Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
}
Pkt6Ptr
-Dhcpv6Srv::processRelease(const Pkt6Ptr& release,
- NameChangeRequestPtr&) {
+Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
sanityCheck(release, MANDATORY, MANDATORY);
@@ -1236,7 +1459,7 @@ Dhcpv6Srv::processRelease(const Pkt6Ptr& release,
// @todo If client sent a release and we should remove outstanding
// DNS records.
- return reply;
+ return (reply);
}
Pkt6Ptr
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index c3a184d..c94328a 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -29,6 +29,7 @@
#include <boost/noncopyable.hpp>
#include <iostream>
+#include <queue>
namespace isc {
namespace dhcp {
@@ -130,20 +131,17 @@ protected:
/// @param request a message received from client
///
/// @return REPLY message or NULL
- Pkt6Ptr processRequest(const Pkt6Ptr& request,
- isc::d2::NameChangeRequestPtr& ncr);
+ Pkt6Ptr processRequest(const Pkt6Ptr& request);
/// @brief Stub function that will handle incoming RENEW messages.
///
/// @param renew message received from client
- Pkt6Ptr processRenew(const Pkt6Ptr& renew,
- isc::d2::NameChangeRequestPtr& ncr);
+ Pkt6Ptr processRenew(const Pkt6Ptr& renew);
/// @brief Stub function that will handle incoming REBIND messages.
///
/// @param rebind message received from client
- Pkt6Ptr processRebind(const Pkt6Ptr& rebind,
- isc::d2::NameChangeRequestPtr& ncr);
+ Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
/// @brief Stub function that will handle incoming CONFIRM messages.
///
@@ -153,8 +151,7 @@ protected:
/// @brief Stub function that will handle incoming RELEASE messages.
///
/// @param release message received from client
- Pkt6Ptr processRelease(const Pkt6Ptr& release,
- isc::d2::NameChangeRequestPtr& ncr);
+ Pkt6Ptr processRelease(const Pkt6Ptr& release);
/// @brief Stub function that will handle incoming DECLINE messages.
///
@@ -191,11 +188,14 @@ protected:
/// @param duid client's duid
/// @param question client's message (typically SOLICIT or REQUEST)
/// @param ia pointer to client's IA_NA option (client's request)
+ /// @param fqdn A DHCPv6 Client FQDN %Option generated in a response to the
+ /// FQDN option sent by a client.
/// @return IA_NA option (server's response)
OptionPtr assignIA_NA(const isc::dhcp::Subnet6Ptr& subnet,
const isc::dhcp::DuidPtr& duid,
isc::dhcp::Pkt6Ptr question,
- boost::shared_ptr<Option6IA> ia);
+ Option6IAPtr ia,
+ const Option6ClientFqdnPtr& fqdn);
/// @brief Renews specific IA_NA option
///
@@ -207,9 +207,11 @@ protected:
/// @param duid client's duid
/// @param question client's message
/// @param ia IA_NA option that is being renewed
+ /// @param fqdn DHCPv6 Client FQDN Option included in the server's response
/// @return IA_NA option (server's response)
OptionPtr renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
- Pkt6Ptr question, boost::shared_ptr<Option6IA> ia);
+ Pkt6Ptr question, boost::shared_ptr<Option6IA> ia,
+ const Option6ClientFqdnPtr& fqdn);
/// @brief Releases specific IA_NA option
///
@@ -268,7 +270,10 @@ protected:
///
/// @param question client's message (with requested IA_NA)
/// @param answer server's message (IA_NA options will be added here)
- void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer);
+ /// @param fqdn an FQDN option generated in a response to the client's
+ /// FQDN option.
+ void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& fqdn);
/// @brief Processes Client FQDN Option.
///
@@ -288,24 +293,56 @@ protected:
/// held in this function.
///
/// @param question Client's message.
- /// @param answer Server's response to the client.
- void processClientFqdn(const Pkt6Ptr& question, Pkt6Ptr& answer,
- d2::NameChangeRequestPtr& ncr);
-
- /// @brief Creates a @c isc::d2::NameChangeRequest based on the DHCPv6
- /// Client FQDN %Option stored in the response to the client.
- ///
- /// The @c isc:d2::NameChangeRequest class encapsulates the request from
- /// the DHCPv6 server to the DHCP-DDNS module to perform DNS Update.
///
- /// @param answer A response being sent to a client.
+ /// @return FQDN option produced in the response to the client's message.
+ Option6ClientFqdnPtr processClientFqdn(const Pkt6Ptr& question);
+
+ /// @brief Adds DHCPv6 Client FQDN %Option to the server response.
+ ///
+ /// This function will add the specified FQDN option into the server's
+ /// response when FQDN is not NULL and server is either configured to
+ /// always include the FQDN in the response or client requested it using
+ /// %Option Request %Option.
+ /// This function is exception safe.
+ ///
+ /// @param question A message received from the client.
+ /// @param [out] answer A server's response where FQDN option will be added.
+ /// @param fqdn A DHCPv6 Client FQDN %Option to be added.
+ void appendClientFqdn(const Pkt6Ptr& question,
+ Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& fqdn);
+
+ /// @brief Creates a number of @c isc::d2::NameChangeRequest objects based
+ /// on the DHCPv6 Client FQDN %Option.
+ ///
+ /// The @c isc::d2::NameChangeRequest class encapsulates the request from
+ /// the DHCPv6 server to the DHCP-DDNS module to perform DNS Update. The
+ /// FQDN option carries response to the client about DNS updates that
+ /// server intents to perform for the DNS client. Based on this, the
+ /// function will create zero or more @c isc::d2::NameChangeRequest objects
+ /// and store them in the internal queue. Requests created by this function
+ /// are only adding or updating DNS records. In order to generate requests
+ /// for DNS records removal, use @c createRemovalNameChangeRequest.
+ ///
+ /// @param answer A message beging sent to the Client.
/// @param fqdn_answer A DHCPv6 Client FQDN %Option which is included in the
/// response message sent to a client.
- /// @param [out] ncr A @c isc::d2::NameChangeRequest object to be sent to
- /// the DHCP-DDNS module as a result of the Client FQDN %Option processing.
- void createNameChangeRequest(const Pkt6Ptr& answer,
- const Option6ClientFqdnPtr& fqdn_answer,
- isc::d2::NameChangeRequestPtr& ncr);
+ void createNameChangeRequests(const Pkt6Ptr& answer,
+ const Option6ClientFqdnPtr& fqdn_answer);
+
+ /// @brief Creates a @c isc::d2::NameChangeRequest which requests removal
+ /// of DNS entries for a particular lease.
+ ///
+ /// This function should be called upon removal of the lease from the lease
+ /// database, i.e, when client sent Release or Decline message. It will
+ /// create a single @isc::d2::NameChangeRequest which removes the existing
+ /// DNS records for the lease, which server is responsible for. Note that
+ /// this function will not remove the entries which server hadn't added.
+ /// This is the case, when client performs forward DNS update on its own.
+ ///
+ /// @param lease A lease for which the the removal of correponding DNS
+ /// records will be performed.
+ void createRemovalNameChangeRequest(const Lease6Ptr& lease);
/// @brief Attempts to renew received addresses
///
@@ -315,7 +352,10 @@ protected:
/// as IA_NA/IAADDR to reply packet.
/// @param renew client's message asking for renew
/// @param reply server's response
- void renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply);
+ /// @param fqdn A DHCPv6 Client FQDN %Option generated in the response to the
+ /// client's FQDN option.
+ void renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply,
+ const Option6ClientFqdnPtr& fqdn);
/// @brief Attempts to release received addresses
///
@@ -377,6 +417,12 @@ private:
/// Indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown_;
+
+protected:
+
+ /// Holds a list of @c isc::d2::NameChangeRequest objects, which
+ /// are waiting for sending to D2 module.
+ std::queue<isc::d2::NameChangeRequest> name_change_reqs_;
};
}; // namespace isc::dhcp
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index a2e2ed0..0fec35b 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -55,6 +55,11 @@ dhcp6_unittests_SOURCES += ../dhcp6_srv.h ../dhcp6_srv.cc
dhcp6_unittests_SOURCES += ../dhcp6_log.h ../dhcp6_log.cc
dhcp6_unittests_SOURCES += ../ctrl_dhcp6_srv.cc
dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
+
+# Temporarily compile this file here. It will be removed once libdhcp-ddns
+# is implemented which will include this file and other files required
+# by DHCPv6.
+dhcp6_unittests_SOURCES += ../../d2/ncr_msg.cc ../../d2/ncr_msg.h
nodist_dhcp6_unittests_SOURCES = ../dhcp6_messages.h ../dhcp6_messages.cc
dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 597d954..09ed4e5 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -79,11 +79,14 @@ public:
using Dhcpv6Srv::processRenew;
using Dhcpv6Srv::processRelease;
using Dhcpv6Srv::processClientFqdn;
+ using Dhcpv6Srv::createNameChangeRequests;
+ using Dhcpv6Srv::createRemovalNameChangeRequest;
using Dhcpv6Srv::createStatusCode;
using Dhcpv6Srv::selectSubnet;
using Dhcpv6Srv::sanityCheck;
using Dhcpv6Srv::loadServerID;
using Dhcpv6Srv::writeServerID;
+ using Dhcpv6Srv::name_change_reqs_;
};
static const char* DUID_FILE = "server-id-test.txt";
@@ -246,9 +249,6 @@ public:
int rcode_;
ConstElementPtr comment_;
-
- // A NameChangeRequest used in many tests.
- NameChangeRequestPtr ncr_;
};
// Provides suport for tests against a preconfigured subnet6
@@ -344,14 +344,31 @@ public:
};
-class FqdnDhcpv6SrvTest : public NakedDhcpv6SrvTest {
+class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
public:
- FqdnDhcpv6SrvTest() {
+ FqdnDhcpv6SrvTest()
+ : Dhcpv6SrvTest() {
+ // generateClientId assigns DUID to duid_.
+ generateClientId();
+ lease_.reset(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1"),
+ duid_, 1234, 501, 502, 503,
+ 504, 1, 0));
+
}
virtual ~FqdnDhcpv6SrvTest() {
}
+ Option6ClientFqdnPtr
+ createClientFqdn(const uint8_t flags,
+ const std::string& fqdn_name,
+ const Option6ClientFqdn::DomainNameType fqdn_type) {
+ return (Option6ClientFqdnPtr(new Option6ClientFqdn(flags,
+ fqdn_name,
+ fqdn_type)));
+ }
+
+ // Create a message holding DHCPv6 Client FQDN Option.
Pkt6Ptr generatePktWithFqdn(uint8_t msg_type,
const uint8_t fqdn_flags,
const std::string& fqdn_domain_name,
@@ -361,16 +378,23 @@ public:
OptionPtr srvid = OptionPtr()) {
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
- pkt->addOption(generateIA(234, 1500, 3000));
+ Option6IAPtr ia = generateIA(234, 1500, 3000);
+
+ if (msg_type != DHCPV6_REPLY) {
+ IOAddress hint("2001:db8:1:1::dead:beef");
+ OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+ ia->addOption(hint_opt);
+ pkt->addOption(ia);
+ }
+
OptionPtr clientid = generateClientId();
pkt->addOption(clientid);
if (srvid && (msg_type != DHCPV6_SOLICIT)) {
pkt->addOption(srvid);
}
- pkt->addOption(OptionPtr(new Option6ClientFqdn(fqdn_flags,
- fqdn_domain_name,
- fqdn_type)));
+ pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
+ fqdn_type));
if (include_oro) {
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6,
@@ -382,12 +406,65 @@ public:
return (pkt);
}
+ // Creates instance of the DHCPv6 message with client id and server id.
+ Pkt6Ptr generateMessageWithIds(const uint8_t msg_type,
+ NakedDhcpv6Srv& srv) {
+ Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
+ // Generate client-id.
+ OptionPtr opt_clientid = generateClientId();
+ pkt->addOption(opt_clientid);
+
+ if (msg_type != DHCPV6_SOLICIT) {
+ // Generate server-id.
+ pkt->addOption(srv.getServerID());
+ }
+
+ return (pkt);
+ }
+
// Returns an instance of the option carrying FQDN.
Option6ClientFqdnPtr getClientFqdnOption(const Pkt6Ptr& pkt) {
return (boost::dynamic_pointer_cast<Option6ClientFqdn>
(pkt->getOption(D6O_CLIENT_FQDN)));
}
+ // Adds IA option to the message. Option holds an address.
+ void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt) {
+ Option6IAPtr opt_ia = generateIA(iaid, 1500, 3000);
+ Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
+ 300, 500));
+ opt_ia->addOption(opt_iaaddr);
+ pkt->addOption(opt_ia);
+ }
+
+ // Adds IA option to the message. Option holds status code.
+ void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt) {
+ Option6IAPtr opt_ia = generateIA(iaid, 1500, 3000);
+ addStatusCode(status_code, "", opt_ia);
+ pkt->addOption(opt_ia);
+ }
+
+ // Creates status code with the specified code and message.
+ OptionCustomPtr createStatusCode(const uint16_t code,
+ const std::string& msg) {
+ OptionDefinition def("status-code", D6O_STATUS_CODE, "record");
+ def.addRecordField("uint16");
+ def.addRecordField("string");
+ OptionCustomPtr opt_status(new OptionCustom(def, Option::V6));
+ opt_status->writeInteger(code);
+ if (!msg.empty()) {
+ opt_status->writeString(msg, 1);
+ }
+ return (opt_status);
+ }
+
+ // Adds Status Code option to the IA.
+ void addStatusCode(const uint16_t code, const std::string& msg,
+ Option6IAPtr& opt_ia) {
+ opt_ia->addOption(createStatusCode(code, msg));
+ }
+
+ // Test processing of the DHCPv6 Client FQDN Option.
void testFqdn(const uint16_t msg_type,
const bool use_oro,
const uint8_t in_flags,
@@ -403,18 +480,8 @@ public:
use_oro);
ASSERT_TRUE(getClientFqdnOption(question));
- Pkt6Ptr answer;
- if (msg_type == DHCPV6_SOLICIT) {
- answer.reset(new Pkt6(DHCPV6_ADVERTISE, 1234));
-
- } else {
- answer.reset(new Pkt6(DHCPV6_REPLY, 1234));
-
- }
-
- ASSERT_NO_THROW(srv.processClientFqdn(question, answer, ncr_));
-
- Option6ClientFqdnPtr answ_fqdn = getClientFqdnOption(answer);
+ Option6ClientFqdnPtr answ_fqdn;
+ ASSERT_NO_THROW(answ_fqdn = srv.processClientFqdn(question));
ASSERT_TRUE(answ_fqdn);
const bool flag_n = (exp_flags & Option6ClientFqdn::FLAG_N) != 0 ?
@@ -431,6 +498,89 @@ public:
EXPECT_EQ(exp_domain_name, answ_fqdn->getDomainName());
EXPECT_EQ(Option6ClientFqdn::FULL, answ_fqdn->getDomainNameType());
}
+
+ // Tests that the client message holding an FQDN is processed and the
+ // lease is acquired.
+ void testProcessMessage(const uint8_t msg_type,
+ const std::string& hostname,
+ NakedDhcpv6Srv& srv) {
+ // Create a message of a specified type, add server id and
+ // FQDN option.
+ OptionPtr srvid = srv.getServerID();
+ Pkt6Ptr req = generatePktWithFqdn(msg_type, FQDN_FLAG_S,
+ hostname,
+ Option6ClientFqdn::FULL,
+ true, srvid);
+
+ // For different client's message types we have to invoke different
+ // functions to generate response.
+ Pkt6Ptr reply;
+ if (msg_type == DHCPV6_SOLICIT) {
+ ASSERT_NO_THROW(reply = srv.processSolicit(req));
+
+ } else if (msg_type == DHCPV6_REQUEST) {
+ ASSERT_NO_THROW(reply = srv.processRequest(req));
+
+ } else if (msg_type == DHCPV6_RENEW) {
+ ASSERT_NO_THROW(reply = srv.processRequest(req));
+
+ } else if (msg_type == DHCPV6_RELEASE) {
+ // For Release no lease will be acquired so we have to leave
+ // function here.
+ ASSERT_NO_THROW(reply = srv.processRelease(req));
+ return;
+ } else {
+ // We are not interested in testing other message types.
+ return;
+ }
+
+ // For Solicit, we will get different message type obviously.
+ if (msg_type == DHCPV6_SOLICIT) {
+ checkResponse(reply, DHCPV6_ADVERTISE, 1234);
+
+ } else {
+ checkResponse(reply, DHCPV6_REPLY, 1234);
+ }
+
+ // Check verify that IA_NA is correct.
+ Option6IAAddrPtr addr =
+ checkIA_NA(reply, 234, subnet_->getT1(), subnet_->getT2());
+ ASSERT_TRUE(addr);
+
+ // Check that we have got the address we requested.
+ checkIAAddr(addr, IOAddress("2001:db8:1:1::dead:beef"),
+ subnet_->getPreferred(),
+ subnet_->getValid());
+
+ if (msg_type != DHCPV6_SOLICIT) {
+ // Check that the lease exists.
+ Lease6Ptr lease =
+ checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
+ ASSERT_TRUE(lease);
+ }
+ }
+
+ // Verify that NameChangeRequest holds valid values.
+ void verifyNameChangeRequest(NakedDhcpv6Srv& srv,
+ const isc::d2::NameChangeType type,
+ const bool reverse, const bool forward,
+ const std::string& addr,
+ const std::string& dhcid,
+ const uint16_t expires,
+ const uint16_t len) {
+ NameChangeRequest ncr = srv.name_change_reqs_.front();
+ EXPECT_EQ(type, ncr.getChangeType());
+ EXPECT_EQ(forward, ncr.isForwardChange());
+ EXPECT_EQ(reverse, ncr.isReverseChange());
+ EXPECT_EQ(addr, ncr.getIpAddress());
+ EXPECT_EQ(dhcid, ncr.getDhcid().toStr());
+ EXPECT_EQ(expires, ncr.getLeaseExpiresOn());
+ EXPECT_EQ(len, ncr.getLeaseLength());
+ EXPECT_EQ(isc::d2::ST_NEW, ncr.getStatus());
+ srv.name_change_reqs_.pop();
+ }
+
+ Lease6Ptr lease_;
};
// This test verifies that incoming SOLICIT can be handled properly when
@@ -481,7 +631,7 @@ TEST_F(NakedDhcpv6SrvTest, RequestNoSubnet) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRequest(req, ncr_);
+ Pkt6Ptr reply = srv.processRequest(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail);
@@ -516,7 +666,7 @@ TEST_F(NakedDhcpv6SrvTest, RenewNoSubnet) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
+ Pkt6Ptr reply = srv.processRenew(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
@@ -551,7 +701,7 @@ TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
+ Pkt6Ptr reply = srv.processRelease(req);
// check that we get the right NAK
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
@@ -1019,7 +1169,7 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRequest(req, ncr_);
+ Pkt6Ptr reply = srv.processRequest(req);
// check if we get response at all
checkResponse(reply, DHCPV6_REPLY, 1234);
@@ -1084,9 +1234,9 @@ TEST_F(Dhcpv6SrvTest, ManyRequests) {
req3->addOption(srv.getServerID());
// Pass it to the server and get an advertise
- Pkt6Ptr reply1 = srv.processRequest(req1, ncr_);
- Pkt6Ptr reply2 = srv.processRequest(req2, ncr_);
- Pkt6Ptr reply3 = srv.processRequest(req3, ncr_);
+ Pkt6Ptr reply1 = srv.processRequest(req1);
+ Pkt6Ptr reply2 = srv.processRequest(req2);
+ Pkt6Ptr reply3 = srv.processRequest(req3);
// check if we get response at all
checkResponse(reply1, DHCPV6_REPLY, 1234);
@@ -1181,7 +1331,7 @@ TEST_F(Dhcpv6SrvTest, RenewBasic) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
+ Pkt6Ptr reply = srv.processRenew(req);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, 1234);
@@ -1267,7 +1417,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
// Case 1: No lease known to server
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
+ Pkt6Ptr reply = srv.processRenew(req);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, transid);
@@ -1293,7 +1443,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Pass it to the server and hope for a REPLY
- reply = srv.processRenew(req, ncr_);
+ reply = srv.processRenew(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
@@ -1312,7 +1462,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
req->addOption(generateClientId(13)); // generate different DUID
// (with length 13)
- reply = srv.processRenew(req, ncr_);
+ reply = srv.processRenew(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
@@ -1375,7 +1525,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseBasic) {
req->addOption(srv.getServerID());
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
+ Pkt6Ptr reply = srv.processRelease(req);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, 1234);
@@ -1453,7 +1603,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
SCOPED_TRACE("CASE 1: No lease known to server");
// Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
+ Pkt6Ptr reply = srv.processRelease(req);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, transid);
@@ -1477,7 +1627,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Pass it to the server and hope for a REPLY
- reply = srv.processRelease(req, ncr_);
+ reply = srv.processRelease(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
@@ -1500,7 +1650,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
req->addOption(generateClientId(13)); // generate different DUID
// (with length 13)
- reply = srv.processRelease(req, ncr_);
+ reply = srv.processRelease(req);
checkResponse(reply, DHCPV6_REPLY, transid);
tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
@@ -1903,6 +2053,325 @@ TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
"myhost.example.com.");
}
+// Test that exception is thrown if supplied NULL answer packet when
+// creating NameChangeRequests.
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAnswer) {
+ NakedDhcpv6Srv srv(0);
+
+ Pkt6Ptr answer;
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
+ "myhost.example.com",
+ Option6ClientFqdn::FULL);
+ EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
+ isc::Unexpected);
+
+}
+
+// Test that exception is thrown if supplied answer from the server
+// contains no DUID when creating NameChangeRequests.
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoDUID) {
+ NakedDhcpv6Srv srv(0);
+
+ Pkt6Ptr answer = Pkt6Ptr(new Pkt6(DHCPV6_REPLY, 1234));
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
+ "myhost.example.com",
+ Option6ClientFqdn::FULL);
+
+ EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
+ isc::Unexpected);
+
+}
+
+// Test no NameChangeRequests are added if FQDN option is NULL.
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoFQDN) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create Reply message with Client Id and Server id.
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
+
+ // Pass NULL FQDN option. No NameChangeRequests should be created.
+ Option6ClientFqdnPtr fqdn;
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
+
+ // There should be no new NameChangeRequests.
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
+}
+
+// Test that NameChangeRequests are not generated if an answer message
+// contains no addresses.
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAddr) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create Reply message with Client Id and Server id.
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
+
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
+ "myhost.example.com",
+ Option6ClientFqdn::FULL);
+
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
+
+ // We didn't add any IAs, so there should be no NameChangeRequests in th
+ // queue.
+ ASSERT_TRUE(srv.name_change_reqs_.empty());
+}
+
+// Test that a number of NameChangeRequests is created as a result of
+// processing the answer message which holds 3 IAs and when FQDN is
+// specified.
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create Reply message with Client Id and Server id.
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
+
+ // Create three IAs, each having different address.
+ addIA(1234, IOAddress("2001:db8:1::1"), answer);
+ addIA(2345, IOAddress("2001:db8:1::2"), answer);
+ addIA(3456, IOAddress("2001:db8:1::3"), answer);
+
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
+ "myhost.example.com",
+ Option6ClientFqdn::FULL);
+
+ // Create NameChangeRequests. Since we have added 3 IAs, it should
+ // result in generation of 3 distinct NameChangeRequests.
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
+ ASSERT_EQ(3, srv.name_change_reqs_.size());
+
+ // Verify that NameChangeRequests are correct. Each call to the
+ // verifyNameChangeRequest will pop verified request from the queue.
+
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::1",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 500);
+
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::2",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 500);
+
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::3",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 500);
+
+}
+
+// Test creation of the NameChangeRequest to remove both forward and reverse
+// mapping for the given lease.
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
+ NakedDhcpv6Srv srv(0);
+
+ lease_->fqdn_fwd_ = true;
+ lease_->fqdn_rev_ = true;
+ lease_->hostname_ = "myhost.example.com.";
+
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
+ "2001:db8:1::1",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 502);
+
+}
+
+// Test creation of the NameChangeRequest to remove reverse mapping for the
+// given lease.
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
+ NakedDhcpv6Srv srv(0);
+
+ lease_->fqdn_fwd_ = false;
+ lease_->fqdn_rev_ = true;
+ lease_->hostname_ = "myhost.example.com.";
+
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, false,
+ "2001:db8:1::1",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 502);
+
+}
+
+// Test that NameChangeRequest to remove DNS records is not generated when
+// neither forward nor reverse DNS update has been performed for a lease.
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoUpdate) {
+ NakedDhcpv6Srv srv(0);
+
+ lease_->fqdn_fwd_ = false;
+ lease_->fqdn_rev_ = false;
+
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
+
+}
+
+// Test that NameChangeRequest is not generated if the hostname hasn't been
+// specified for a lease for which forward and reverse mapping has been set.
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoHostname) {
+ NakedDhcpv6Srv srv(0);
+
+ lease_->fqdn_fwd_ = true;
+ lease_->fqdn_rev_ = true;
+ lease_->hostname_ = "";
+
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
+
+}
+
+// Test that NameChangeRequest is not generated if the invalid hostname has
+// been specified for a lease for which forward and reverse mapping has been
+// set.
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestWrongHostname) {
+ NakedDhcpv6Srv srv(0);
+
+ lease_->fqdn_fwd_ = true;
+ lease_->fqdn_rev_ = true;
+ lease_->hostname_ = "myhost..example.com.";
+
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
+
+}
+
+// Test that Advertise message generated in a response to the Solicit will
+// not result in generation if the NameChangeRequests.
+TEST_F(FqdnDhcpv6SrvTest, processSolicit) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create a Solicit message with FQDN option and generate server's
+ // response using processRequest function. This will result in the
+ // creation of a new lease and the appropriate NameChangeRequest
+ // to add both reverse and forward mapping to DNS.
+ testProcessMessage(DHCPV6_SOLICIT, "myhost.example.com", srv);
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
+}
+
+// Test that client may send two requests, each carrying FQDN option with
+// a different domain-name. Server should use existing lease for the second
+// request but modify the DNS entries for the lease according to the contents
+// of the FQDN sent in the second request.
+TEST_F(FqdnDhcpv6SrvTest, processTwoRequests) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create a Request message with FQDN option and generate server's
+ // response using processRequest function. This will result in the
+ // creation of a new lease and the appropriate NameChangeRequest
+ // to add both reverse and forward mapping to DNS.
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+
+ // Client may send another request message with a new domain-name. In this
+ // case the same lease will be returned. The existing DNS entry needs to
+ // be replaced with a new one. Server should determine that the different
+ // FQDN has been already added to the DNS. As a result, the old DNS
+ // entries should be removed and the entries for the new domain-name
+ // should be added. Therefore, we expect two NameChangeRequests. One to
+ // remove the existing entries, one to add new entries.
+ testProcessMessage(DHCPV6_REQUEST, "otherhost.example.com", srv);
+ ASSERT_EQ(2, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201D422AA463306223D269B6CB7AFE7AAD265FC"
+ "EA97F93623019B2E0D14E5323D5A",
+ 0, 4000);
+
+}
+
+// Test that client may send Request followed by the Renew, both holding
+// FQDN options, but each option holding different domain-name. The Renew
+// should result in generation of the two NameChangeRequests, one to remove
+// DNS entry added previously when Request was processed, another one to
+// add a new entry for the FQDN held in the Renew.
+TEST_F(FqdnDhcpv6SrvTest, processRequestRenew) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create a Request message with FQDN option and generate server's
+ // response using processRequest function. This will result in the
+ // creation of a new lease and the appropriate NameChangeRequest
+ // to add both reverse and forward mapping to DNS.
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+
+ // Client may send Renew message with a new domain-name. In this
+ // case the same lease will be returned. The existing DNS entry needs to
+ // be replaced with a new one. Server should determine that the different
+ // FQDN has been already added to the DNS. As a result, the old DNS
+ // entries should be removed and the entries for the new domain-name
+ // should be added. Therefore, we expect two NameChangeRequests. One to
+ // remove the existing entries, one to add new entries.
+ testProcessMessage(DHCPV6_RENEW, "otherhost.example.com", srv);
+ ASSERT_EQ(2, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201D422AA463306223D269B6CB7AFE7AAD265FC"
+ "EA97F93623019B2E0D14E5323D5A",
+ 0, 4000);
+
+}
+
+TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) {
+ NakedDhcpv6Srv srv(0);
+
+ // Create a Request message with FQDN option and generate server's
+ // response using processRequest function. This will result in the
+ // creation of a new lease and the appropriate NameChangeRequest
+ // to add both reverse and forward mapping to DNS.
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+
+ // Client may send Release message. In this case the lease should be
+ // removed and all existing DNS entries for this lease should be
+ // also removed. Therefore, we expect that single NameChangeRequest to
+ // remove DNS entries is generated.
+ testProcessMessage(DHCPV6_RELEASE, "otherhost.example.com", srv);
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
+ "2001:db8:1:1::dead:beef",
+ "000201415AA33D1187D148275136FA30300478"
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
+ 0, 4000);
+
+}
+
+
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
diff --git a/src/lib/dhcp/option6_client_fqdn.cc b/src/lib/dhcp/option6_client_fqdn.cc
index 1a1ba5d..5fcb81d 100644
--- a/src/lib/dhcp/option6_client_fqdn.cc
+++ b/src/lib/dhcp/option6_client_fqdn.cc
@@ -280,6 +280,20 @@ Option6ClientFqdn::getDomainName() const {
}
void
+Option6ClientFqdn::packDomainName(isc::util::OutputBuffer& buf) const {
+ // Domain name, encoded as a set of labels.
+ isc::dns::LabelSequence labels(*impl_->domain_name_);
+ if (labels.getDataLength() > 0) {
+ size_t read_len = 0;
+ const uint8_t* data = labels.getData(&read_len);
+ if (impl_->domain_name_type_ == PARTIAL) {
+ --read_len;
+ }
+ buf.writeData(data, read_len);
+ }
+}
+
+void
Option6ClientFqdn::setDomainName(const std::string& domain_name,
const DomainNameType domain_name_type) {
impl_->setDomainName(domain_name, domain_name_type);
@@ -301,18 +315,8 @@ Option6ClientFqdn::pack(isc::util::OutputBuffer& buf) {
packHeader(buf);
// Flags field.
buf.writeUint8(impl_->flags_);
- // Domain name, encoded as a set of labels.
- isc::dns::LabelSequence labels(*impl_->domain_name_);
- if (labels.getDataLength() > 0) {
- size_t read_len = 0;
- const uint8_t* data = labels.getData(&read_len);
- if (impl_->domain_name_type_ == PARTIAL) {
- --read_len;
- }
- buf.writeData(data, read_len);
- }
-
-
+ // Domain name.
+ packDomainName(buf);
}
void
diff --git a/src/lib/dhcp/option6_client_fqdn.h b/src/lib/dhcp/option6_client_fqdn.h
index bc139e3..8815273 100644
--- a/src/lib/dhcp/option6_client_fqdn.h
+++ b/src/lib/dhcp/option6_client_fqdn.h
@@ -182,6 +182,13 @@ public:
/// @return domain-name in the text format.
std::string getDomainName() const;
+ /// @brief Writes domain-name in the wire format into a buffer.
+ ///
+ /// The data being written are appended at the end of the buffer.
+ ///
+ /// @param [out] buf buffer where domain-name will be written.
+ void packDomainName(isc::util::OutputBuffer& buf) const;
+
/// @brief Set new domain-name.
///
/// @param domain_name domain name field value in the text format.
diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h
index 32f3667..e4e4d11 100644
--- a/src/lib/dhcp/option6_ia.h
+++ b/src/lib/dhcp/option6_ia.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -16,12 +16,17 @@
#define OPTION_IA_H
#include <dhcp/option.h>
-
+#include <boost/shared_ptr.hpp>
#include <stdint.h>
namespace isc {
namespace dhcp {
+class Option6IA;
+
+/// A pointer to the @c Option6IA object.
+typedef boost::shared_ptr<Option6IA> Option6IAPtr;
+
class Option6IA: public Option {
public:
diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h
index 28c5abc..cb85bed 100644
--- a/src/lib/dhcp/option6_iaaddr.h
+++ b/src/lib/dhcp/option6_iaaddr.h
@@ -17,10 +17,16 @@
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <boost/shared_ptr.hpp>
namespace isc {
namespace dhcp {
+class Option6IAAddr;
+
+/// A pointer to the @c isc::dhcp::Option6IAAddr object.
+typedef boost::shared_ptr<Option6IAAddr> Option6IAAddrPtr;
+
class Option6IAAddr: public Option {
public:
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
index 9c5bdeb..d3fdd0b 100644
--- a/src/lib/dhcpsrv/alloc_engine.cc
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -168,6 +168,9 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& hint,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation /* = false */ ) {
try {
@@ -201,7 +204,10 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
/// implemented
// the hint is valid and not currently used, let's create a lease for it
- Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, fake_allocation);
+ Lease6Ptr lease = createLease6(subnet, duid, iaid,
+ hint, fwd_dns_update,
+ rev_dns_update, hostname,
+ 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
@@ -212,7 +218,8 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
} else {
if (existing->expired()) {
return (reuseExpiredLease(existing, subnet, duid, iaid,
- fake_allocation));
+ fwd_dns_update, rev_dns_update,
+ hostname, fake_allocation));
}
}
@@ -246,7 +253,8 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
// there's no existing lease for selected candidate, so it is
// free. Let's allocate it.
Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
- fake_allocation);
+ fwd_dns_update, rev_dns_update,
+ hostname, fake_allocation);
if (lease) {
return (lease);
}
@@ -257,7 +265,8 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
} else {
if (existing->expired()) {
return (reuseExpiredLease(existing, subnet, duid, iaid,
- fake_allocation));
+ fwd_dns_update, rev_dns_update,
+ hostname, fake_allocation));
}
}
@@ -438,6 +447,9 @@ Lease6Ptr AllocEngine::reuseExpiredLease(Lease6Ptr& expired,
const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation /*= false */ ) {
if (!expired->expired()) {
@@ -454,9 +466,9 @@ Lease6Ptr AllocEngine::reuseExpiredLease(Lease6Ptr& expired,
expired->cltt_ = time(NULL);
expired->subnet_id_ = subnet->getID();
expired->fixed_ = false;
- expired->hostname_ = std::string("");
- expired->fqdn_fwd_ = false;
- expired->fqdn_rev_ = false;
+ expired->hostname_ = hostname;
+ expired->fqdn_fwd_ = fwd_dns_update;
+ expired->fqdn_rev_ = rev_dns_update;
/// @todo: log here that the lease was reused (there's ticket #2524 for
/// logging in libdhcpsrv)
@@ -517,12 +529,19 @@ Lease6Ptr AllocEngine::createLease6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& addr,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation /*= false */ ) {
Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid, iaid,
subnet->getPreferred(), subnet->getValid(),
subnet->getT1(), subnet->getT2(), subnet->getID()));
+ lease->fqdn_fwd_ = fwd_dns_update;
+ lease->fqdn_rev_ = rev_dns_update;
+ lease->hostname_ = hostname;
+
if (!fake_allocation) {
// That is a real (REQUEST) allocation
bool status = LeaseMgrFactory::instance().addLease(lease);
diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h
index 7e3d136..40f1d3d 100644
--- a/src/lib/dhcpsrv/alloc_engine.h
+++ b/src/lib/dhcpsrv/alloc_engine.h
@@ -233,6 +233,11 @@ protected:
/// @param duid Client's DUID
/// @param iaid iaid field from the IA_NA container that client sent
/// @param hint a hint that the client provided
+ /// @param fwd_dns_update A boolean value which indicates that server takes
+ /// responisibility for the forward DNS Update for this lease (if true).
+ /// @param rev_dns_update A boolean value which indicates that server takes
+ /// responibility for the reverse DNS Update for this lease (if true).
+ /// @param hostname A fully qualified domain-name of the client.
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for SOLICIT that is not really allocated (true)
/// @return Allocated IPv6 lease (or NULL if allocation failed)
@@ -241,6 +246,9 @@ protected:
const DuidPtr& duid,
uint32_t iaid,
const isc::asiolink::IOAddress& hint,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation);
/// @brief Destructor. Used during DHCPv6 service shutdown.
@@ -275,13 +283,21 @@ private:
/// @param subnet subnet the lease is allocated from
/// @param duid client's DUID
/// @param iaid IAID from the IA_NA container the client sent to us
- /// @param addr an address that was selected and is confirmed to be available
+ /// @param addr an address that was selected and is confirmed to be
+ /// available
+ /// @param fwd_dns_update A boolean value which indicates that server takes
+ /// responisibility for the forward DNS Update for this lease (if true).
+ /// @param rev_dns_update A boolean value which indicates that server takes
+ /// responibility for the reverse DNS Update for this lease (if true).
+ /// @param hostname A fully qualified domain-name of the client.
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for SOLICIT that is not really allocated (true)
/// @return allocated lease (or NULL in the unlikely case of the lease just
/// becomed unavailable)
Lease6Ptr createLease6(const Subnet6Ptr& subnet, const DuidPtr& duid,
uint32_t iaid, const isc::asiolink::IOAddress& addr,
+ const bool fwd_dns_update, const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation = false);
/// @brief Reuses expired IPv4 lease
@@ -313,12 +329,20 @@ private:
/// @param subnet subnet the lease is allocated from
/// @param duid client's DUID
/// @param iaid IAID from the IA_NA container the client sent to us
+ /// @param fwd_dns_update A boolean value which indicates that server takes
+ /// responisibility for the forward DNS Update for this lease (if true).
+ /// @param rev_dns_update A boolean value which indicates that server takes
+ /// responibility for the reverse DNS Update for this lease (if true).
+ /// @param hostname A fully qualified domain-name of the client.
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for SOLICIT that is not really allocated (true)
/// @return refreshed lease
/// @throw BadValue if trying to recycle lease that is still valid
Lease6Ptr reuseExpiredLease(Lease6Ptr& expired, const Subnet6Ptr& subnet,
const DuidPtr& duid, uint32_t iaid,
+ const bool fwd_dns_update,
+ const bool rev_dns_update,
+ const std::string& hostname,
bool fake_allocation = false);
/// @brief a pointer to currently used allocator
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
index 05f3741..9462439 100644
--- a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -202,7 +202,9 @@ TEST_F(AllocEngine6Test, simpleAlloc6) {
ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
ASSERT_TRUE(engine);
- Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
+ Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("::"), false,
+ false, "",
false);
// Check that we got a lease
@@ -225,8 +227,9 @@ TEST_F(AllocEngine6Test, fakeAlloc6) {
ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
ASSERT_TRUE(engine);
- Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
- true);
+ Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("::"), false,
+ false, "", true);
// Check that we got a lease
ASSERT_TRUE(lease);
@@ -248,6 +251,7 @@ TEST_F(AllocEngine6Test, allocWithValidHint6) {
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("2001:db8:1::15"),
+ false, false, "",
false);
// Check that we got a lease
@@ -286,6 +290,7 @@ TEST_F(AllocEngine6Test, allocWithUsedHint6) {
// twice.
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("2001:db8:1::1f"),
+ false, false, "",
false);
// Check that we got a lease
ASSERT_TRUE(lease);
@@ -319,6 +324,7 @@ TEST_F(AllocEngine6Test, allocBogusHint6) {
// with the normal allocation
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("3000::abc"),
+ false, false, "",
false);
// Check that we got a lease
ASSERT_TRUE(lease);
@@ -345,12 +351,14 @@ TEST_F(AllocEngine6Test, allocateAddress6Nulls) {
// Allocations without subnet are not allowed
Lease6Ptr lease = engine->allocateAddress6(Subnet6Ptr(), duid_, iaid_,
- IOAddress("::"), false);
+ IOAddress("::"),
+ false, false, "", false);
ASSERT_FALSE(lease);
// Allocations without DUID are not allowed either
lease = engine->allocateAddress6(subnet_, DuidPtr(), iaid_,
- IOAddress("::"), false);
+ IOAddress("::"),
+ false, false, "", false);
ASSERT_FALSE(lease);
}
@@ -438,7 +446,9 @@ TEST_F(AllocEngine6Test, smallPool6) {
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
- Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
+ Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("::"),
+ false, false, "",
false);
// Check that we got that single lease
@@ -485,7 +495,8 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
// There is just a single address in the pool and allocated it to someone
// else, so the allocation should fail
Lease6Ptr lease2 = engine->allocateAddress6(subnet_, duid_, iaid_,
- IOAddress("::"), false);
+ IOAddress("::"),
+ false, false, "", false);
EXPECT_FALSE(lease2);
}
@@ -519,6 +530,7 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
// CASE 1: Asking for any address
lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
+ false, false, "",
true);
// Check that we got that single lease
ASSERT_TRUE(lease);
@@ -528,7 +540,9 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
checkLease6(lease);
// CASE 2: Asking specifically for this address
- lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress(addr.toText()),
+ lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress(addr.toText()),
+ false, false, "",
true);
// Check that we got that single lease
ASSERT_TRUE(lease);
@@ -563,7 +577,8 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
// A client comes along, asking specifically for this address
lease = engine->allocateAddress6(subnet_, duid_, iaid_,
- IOAddress(addr.toText()), false);
+ IOAddress(addr.toText()),
+ false, false, "", false);
// Check that he got that single lease
ASSERT_TRUE(lease);
More information about the bind10-changes
mailing list