// Get a lease.
Lease4Ptr lease = alloc_engine_->allocateLease4(*ctx);
- // Tracks whether or not the client name (FQDN or host) has changed since
- // the lease was allocated.
- bool client_name_changed = false;
+ bool reprocess_client_name = false;
+ if (lease) {
+ auto ddns_params = ex.getContext()->getDdnsParams();
+ auto pool = ddns_params->setPoolFromAddress(lease->addr_);
+ if (pool) {
+ reprocess_client_name = pool->hasDdnsParameters();
+ }
+ }
// Subnet may be modified by the allocation engine, if the initial subnet
// belongs to a shared network.
if (subnet && ctx->subnet_ && subnet->getID() != ctx->subnet_->getID()) {
+ // We changed subnets and that means DDNS parameters might be different
+ // so we need to rerun client name processing logic. Arguably we could
+ // compare DDNS parameters for both subnets and then decide if we need
+ // to rerun the name logic, but that's not likely to be any faster than
+ // just re-running the name logic. @todo When inherited parameter
+ // performance is improved this argument could be revisited.
+ // Another case is the new subnet has a reserved hostname.
SharedNetwork4Ptr network;
subnet->getSharedNetwork(network);
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_SUBNET_DYNAMICALLY_CHANGED)
.arg(network ? network->getName() : "<no network?>");
subnet = ctx->subnet_;
-
if (lease) {
- // We changed subnets and that means DDNS parameters might be different
- // so we need to rerun client name processing logic. Arguably we could
- // compare DDNS parameters for both subnets and then decide if we need
- // to rerun the name logic, but that's not likely to be any faster than
- // just re-running the name logic. @todo When inherited parameter
- // performance is improved this argument could be revisited.
- // Another case is the new subnet has a reserved hostname.
-
- // First, we need to remove the prior values from the response and reset
- // those in context, to give processClientName a clean slate.
- resp->delOption(DHO_FQDN);
- resp->delOption(DHO_HOST_NAME);
- ctx->hostname_ = "";
- ctx->fwd_dns_update_ = false;
- ctx->rev_dns_update_ = false;
-
- // Regenerate the name and dns flags.
- processClientName(ex);
-
- // If the results are different from the values already on the
- // lease, flag it so the lease gets updated down below.
- if ((lease->hostname_ != ctx->hostname_) ||
- (lease->fqdn_fwd_ != ctx->fwd_dns_update_) ||
- (lease->fqdn_rev_ != ctx->rev_dns_update_)) {
- lease->hostname_ = ctx->hostname_;
- lease->fqdn_fwd_ = ctx->fwd_dns_update_;
- lease->fqdn_rev_ = ctx->rev_dns_update_;
- client_name_changed = true;
- }
+ reprocess_client_name = true;
+ }
+ }
+
+ // Tracks whether or not the client name (FQDN or host) has changed since
+ // the lease was allocated.
+ bool client_name_changed = false;
+
+ if (reprocess_client_name) {
+ // First, we need to remove the prior values from the response and reset
+ // those in context, to give processClientName a clean slate.
+ resp->delOption(DHO_FQDN);
+ resp->delOption(DHO_HOST_NAME);
+ ctx->hostname_ = "";
+ ctx->fwd_dns_update_ = false;
+ ctx->rev_dns_update_ = false;
+
+ // Regenerate the name and dns flags.
+ processClientName(ex);
+
+ // If the results are different from the values already on the
+ // lease, flag it so the lease gets updated down below.
+ if ((lease->hostname_ != ctx->hostname_) ||
+ (lease->fqdn_fwd_ != ctx->fwd_dns_update_) ||
+ (lease->fqdn_rev_ != ctx->rev_dns_update_)) {
+ lease->hostname_ = ctx->hostname_;
+ lease->fqdn_fwd_ = ctx->fwd_dns_update_;
+ lease->fqdn_rev_ = ctx->rev_dns_update_;
+ client_name_changed = true;
}
}
template<typename LeasePtrType, typename IdentifierType>
void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
const IdentifierType& identifier, const std::string& label,
- NetworkPtr subnet) {
+ const ConstSubnetPtr subnet) {
// Check if there is a need for update.
if (lease->hostname_.empty() || (!lease->fqdn_fwd_ && !lease->fqdn_rev_)
|| !CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
return;
}
- ConflictResolutionMode conflict_resolution_mode = CHECK_WITH_DHCID;
- util::Optional<double> ddns_ttl_percent;
- util::Optional<uint32_t> ddns_ttl;
- util::Optional<uint32_t> ddns_ttl_min;
- util::Optional<uint32_t> ddns_ttl_max;
- if (subnet) {
- auto mode = subnet->getDdnsConflictResolutionMode();
- if (!mode.empty()) {
- conflict_resolution_mode = StringToConflictResolutionMode(mode);
- }
-
- ddns_ttl_percent = subnet->getDdnsTtlPercent();
- ddns_ttl = subnet->getDdnsTtl();
- ddns_ttl_min = subnet->getDdnsTtlMin();
- ddns_ttl_max = subnet->getDdnsTtlMax();
- }
+ ConflictResolutionMode conflict_resolution_mode = CHECK_WITH_DHCID;
+ util::Optional<double> ddns_ttl_percent;
+ util::Optional<uint32_t> ddns_ttl;
+ util::Optional<uint32_t> ddns_ttl_min;
+ util::Optional<uint32_t> ddns_ttl_max;
+ if (subnet) {
+ // Create a DdnsParams so we have access to pool scope values.
+ DdnsParams ddns_params(subnet, true);
+ static_cast<void>(ddns_params.setPoolFromAddress(lease->addr_));
+
+ auto mode = ddns_params.getConflictResolutionMode();
+ if (!mode.empty()) {
+ conflict_resolution_mode = StringToConflictResolutionMode(mode);
+ }
+
+ ddns_ttl_percent = ddns_params.getTtlPercent();
+ ddns_ttl = ddns_params.getTtl();
+ ddns_ttl_min = ddns_params.getTtlMin();
+ ddns_ttl_max = ddns_params.getTtlMax();
+ }
try {
// Create DHCID
if (lease) {
// Figure out from the lease's subnet if we should use conflict resolution.
// If there's no subnet, something hinky is going on so we'll set it true.
- Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()
- ->getCfgSubnets4()->getSubnet(lease->subnet_id_);
+ ConstSubnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()
+ ->getCfgSubnets4()->getSubnet(lease->subnet_id_);
// Client id takes precedence over HW address.
if (lease->client_id_) {
if (lease && (lease->type_ != Lease::TYPE_PD) && lease->duid_) {
// Figure out from the lease's subnet if we should use conflict resolution.
// If there's no subnet, something hinky is going on so we'll set it true.
- Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()
+ ConstSubnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()
->getCfgSubnets6()->getSubnet(lease->subnet_id_);
queueNCRCommon(chg_type, lease, *(lease->duid_),
Pkt6::makeLabel(lease->duid_, lease->hwaddr_), subnet);
ddns_update_on_renew_ = ddns_update_on_renew;
}
-
- /// @brief Returns ib-ddns-conflict-resolution-mode
+ /// @brief Returns ddns-conflict-resolution-mode
///
/// @param inheritance inheritance mode to be used.
util::Optional<std::string>
CfgGlobals::DDNS_CONFLICT_RESOLUTION_MODE));
}
- /// @brief Sets new ib-ddns-conflict-resolution-mode
+ /// @brief Sets new ddns-conflict-resolution-mode
///
/// @param ddns_conflict_resolution_mode New value to use.
void setDdnsConflictResolutionMode(const util::Optional<std::string>& ddns_conflict_resolution_mode) {
return (tmp.str());
}
+bool
+Pool::hasDdnsParameters() {
+ return (!(ddns_send_updates_.unspecified() &&
+ ddns_override_no_update_.unspecified() &&
+ ddns_override_client_update_.unspecified() &&
+ ddns_replace_client_name_mode_.unspecified() &&
+ ddns_generated_prefix_.unspecified() &&
+ ddns_qualifying_suffix_.unspecified() &&
+ ddns_update_on_renew_.unspecified() &&
+ ddns_conflict_resolution_mode_.unspecified() &&
+ ddns_ttl_percent_.unspecified() &&
+ ddns_ttl_.unspecified() &&
+ ddns_ttl_min_.unspecified() &&
+ ddns_ttl_max_.unspecified() &&
+ hostname_char_set_.unspecified() &&
+ hostname_char_replacement_.unspecified()));
+}
+
Pool4::Pool4(const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
: Pool(Lease::TYPE_V4, first, last) {
map->set("pool-id", Element::create(static_cast<long long>(id_)));
}
+ // Add in DDNS paramters for non-prefix pools.
+ if (type_ != Lease::TYPE_PD) {
+ if (!ddns_send_updates_.unspecified()) {
+ map->set("ddns-send-updates", Element::create(ddns_send_updates_));
+ }
+
+ if (!ddns_override_no_update_.unspecified()) {
+ map->set("ddns-override-no-update", Element::create(ddns_override_no_update_));
+ }
+
+ if (!ddns_override_client_update_.unspecified()) {
+ map->set("ddns-override-client-update", Element::create(ddns_override_client_update_));
+ }
+
+ if (!ddns_replace_client_name_mode_.unspecified()) {
+ map->set("ddns-replace-client-name",
+ Element::create(D2ClientConfig::
+ replaceClientNameModeToString(ddns_replace_client_name_mode_)));
+ }
+
+ if (!ddns_generated_prefix_.unspecified()) {
+ map->set("ddns-generated-prefix", Element::create(ddns_generated_prefix_));
+ }
+
+ if (!ddns_qualifying_suffix_.unspecified()) {
+ map->set("ddns-qualifying-suffix", Element::create(ddns_qualifying_suffix_));
+ }
+
+ if (!ddns_update_on_renew_.unspecified()) {
+ map->set("ddns-update-on-renew", Element::create(ddns_update_on_renew_));
+ }
+
+ if (!ddns_conflict_resolution_mode_.unspecified()) {
+ map->set("ddns-conflict-resolution-mode", Element::create(ddns_conflict_resolution_mode_));
+ }
+
+ if (!ddns_ttl_percent_.unspecified()) {
+ map->set("ddns-ttl-percent", Element::create(ddns_ttl_percent_));
+ }
+
+ if (!ddns_ttl_.unspecified()) {
+ map->set("ddns-ttl", Element::create(ddns_ttl_));
+ }
+
+ if (!ddns_ttl_min_.unspecified()) {
+ map->set("ddns-ttl-min", Element::create(ddns_ttl_min_));
+ }
+
+ if (!ddns_ttl_max_.unspecified()) {
+ map->set("ddns-ttl-max", Element::create(ddns_ttl_max_));
+ }
+
+ if (!hostname_char_set_.unspecified()) {
+ map->set("hostname-char-set", Element::create(hostname_char_set_));
+ }
+
+ if (!hostname_char_replacement_.unspecified()) {
+ map->set("hostname-char-replacement", Element::create(hostname_char_replacement_));
+ }
+ }
+
return (map);
}
#include <dhcp/option6_pdexclude.h>
#include <dhcpsrv/allocation_state.h>
#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/d2_client_cfg.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/ip_range_permutation.h>
#include <util/bigints.h>
+#include <util/optional.h>
#include <boost/shared_ptr.hpp>
/// @return A pointer to unparsed pool configuration.
virtual data::ElementPtr toElement() const;
+
+ /// @brief Returns ddns-send-updates
+ util::Optional<bool>
+ getDdnsSendUpdates() const {
+ return (ddns_send_updates_);
+ }
+
+ /// @brief Sets new ddns-send-updates
+ ///
+ /// @param ddns_send_updates New value to use.
+ void setDdnsSendUpdates(const util::Optional<bool>& ddns_send_updates) {
+ ddns_send_updates_ = ddns_send_updates;
+ }
+
+ /// @brief Returns ddns-override-no-update
+ util::Optional<bool>
+ getDdnsOverrideNoUpdate() const {
+ return (ddns_override_no_update_);
+ }
+
+ /// @brief Sets new ddns-override-no-update
+ ///
+ /// @param ddns_override_no_update New value to use.
+ void setDdnsOverrideNoUpdate(const util::Optional<bool>& ddns_override_no_update) {
+ ddns_override_no_update_ = ddns_override_no_update;
+ }
+
+ /// @brief Returns ddns-override-client-update
+ util::Optional<bool>
+ getDdnsOverrideClientUpdate() const {
+ return (ddns_override_client_update_);
+ }
+
+ /// @brief Sets new ddns-override-client-update
+ ///
+ /// @param ddns_override_client_update New value to use.
+ void setDdnsOverrideClientUpdate(const util::Optional<bool>&
+ ddns_override_client_update) {
+ ddns_override_client_update_ = ddns_override_client_update;
+ }
+
+ /// @brief Returns ddns-replace-client-name-mode
+ util::Optional<D2ClientConfig::ReplaceClientNameMode>
+ getDdnsReplaceClientNameMode() const {
+ return (ddns_replace_client_name_mode_);
+ }
+
+ /// @brief Sets new ddns-replace-client-name-mode
+ ///
+ /// @param ddns_replace_client_name_mode New value to use.
+ void
+ setDdnsReplaceClientNameMode(const util::Optional<D2ClientConfig::ReplaceClientNameMode>&
+ ddns_replace_client_name_mode) {
+ ddns_replace_client_name_mode_ = ddns_replace_client_name_mode;
+ }
+
+ /// @brief Returns ddns-generated-prefix
+ util::Optional<std::string>
+ getDdnsGeneratedPrefix() const {
+ return (ddns_generated_prefix_);
+ }
+
+ /// @brief Sets new ddns-generated-prefix
+ ///
+ /// @param ddns_generated_prefix New value to use.
+ void setDdnsGeneratedPrefix(const util::Optional<std::string>& ddns_generated_prefix) {
+ ddns_generated_prefix_ = ddns_generated_prefix;
+ }
+
+ /// @brief Returns ddns-qualifying-suffix
+ util::Optional<std::string>
+ getDdnsQualifyingSuffix() const {
+ return (ddns_qualifying_suffix_);
+ }
+
+ /// @brief Sets new ddns-qualifying-suffix
+ ///
+ /// @param ddns_qualifying_suffix New value to use.
+ void setDdnsQualifyingSuffix(const util::Optional<std::string>& ddns_qualifying_suffix) {
+ ddns_qualifying_suffix_ = ddns_qualifying_suffix;
+ }
+
+ /// @brief Returns ddns-update-on-renew
+ util::Optional<bool>
+ getDdnsUpdateOnRenew() const {
+ return (ddns_update_on_renew_);
+ }
+
+ /// @brief Sets new ddns-update-on-renew
+ ///
+ /// @param ddns_update_on_renew New value to use.
+ void setDdnsUpdateOnRenew(const util::Optional<bool>& ddns_update_on_renew) {
+ ddns_update_on_renew_ = ddns_update_on_renew;
+ }
+
+ /// @brief Returns ddns-conflict-resolution-mode
+ util::Optional<std::string>
+ getDdnsConflictResolutionMode() const {
+ return (ddns_conflict_resolution_mode_);
+ }
+
+ /// @brief Sets new ddns-conflict-resolution-mode
+ ///
+ /// @param ddns_conflict_resolution_mode New value to use.
+ void setDdnsConflictResolutionMode(const util::Optional<std::string>& ddns_conflict_resolution_mode) {
+ ddns_conflict_resolution_mode_ = ddns_conflict_resolution_mode;
+ }
+
+
+ /// @brief Returns ddns-ttl-percent
+ util::Optional<double>
+ getDdnsTtlPercent() const {
+ return (ddns_ttl_percent_);
+ }
+
+ /// @brief Sets new ddns-ttl-percent
+ ///
+ /// @param ddns_ttl_percent New value to use.
+ void setDdnsTtlPercent(const util::Optional<double>& ddns_ttl_percent) {
+ ddns_ttl_percent_ = ddns_ttl_percent;
+ }
+
+ /// @brief Returns ddns-ttl
+ util::Optional<uint32_t>
+ getDdnsTtl() const {
+ return (ddns_ttl_);
+ }
+
+ /// @brief Sets new ddns-ttl
+ ///
+ /// @param ddns_ttl New value to use.
+ void setDdnsTtl(const util::Optional<uint32_t>& ddns_ttl) {
+ ddns_ttl_ = ddns_ttl;
+ }
+
+ /// @brief Returns ddns-ttl-min
+ util::Optional<uint32_t>
+ getDdnsTtlMin() const {
+ return (ddns_ttl_min_);
+ }
+
+ /// @brief Sets new ddns-ttl-min
+ ///
+ /// @param ddns_ttl_min New value to use.
+ void setDdnsTtlMin(const util::Optional<uint32_t>& ddns_ttl_min) {
+ ddns_ttl_min_ = ddns_ttl_min;
+ }
+
+ /// @brief Returns ddns-ttl-max
+ util::Optional<uint32_t>
+ getDdnsTtlMax() const {
+ return (ddns_ttl_max_);
+ }
+
+ /// @brief Sets new ddns-ttl-max
+ ///
+ /// @param ddns_ttl_max New value to use.
+ void setDdnsTtlMax(const util::Optional<uint32_t>& ddns_ttl_max) {
+ ddns_ttl_max_ = ddns_ttl_max;
+ }
+
+ /// @brief Return the char set regexp used to sanitize client hostnames.
+ util::Optional<std::string>
+ getHostnameCharSet() const {
+ return (hostname_char_set_);
+ }
+
+ /// @brief Sets new hostname-char-set
+ ///
+ /// @param hostname_char_set New value to use.
+ void setHostnameCharSet(const util::Optional<std::string>& hostname_char_set) {
+ hostname_char_set_ = hostname_char_set;
+ }
+
+ /// @brief Return the invalid char replacement used to sanitize client hostnames.
+ util::Optional<std::string>
+ getHostnameCharReplacement() const {
+ return (hostname_char_replacement_);
+ }
+
+ /// @brief Sets new hostname-char-replacement
+ ///
+ /// @param hostname_char_replacement New value to use.
+ void setHostnameCharReplacement(const util::Optional<std::string>&
+ hostname_char_replacement) {
+ hostname_char_replacement_ = hostname_char_replacement;
+ }
+
+ /// @brief Checks if any of the DDNS parameters has a value.
+ ///
+ /// @return True if any of the DDNS parameters are specified.
+ bool hasDdnsParameters();
+
protected:
/// @brief protected constructor
/// @brief Holds pool-specific allocation state.
AllocationStatePtr allocation_state_;
+
+ /// @brief Should Kea perform DNS updates. Used to provide scoped enabling
+ /// and disabling of updates.
+ util::Optional<bool> ddns_send_updates_;
+
+ /// @brief Should Kea perform updates, even if client requested no updates.
+ /// Overrides the client request for no updates via the N flag.
+ util::Optional<bool> ddns_override_no_update_;
+
+ /// @brief Should Kea perform updates, even if client requested delegation.
+ util::Optional<bool> ddns_override_client_update_;
+
+ /// @brief How Kea should handle the domain-name supplied by the client.
+ util::Optional<D2ClientConfig::ReplaceClientNameMode> ddns_replace_client_name_mode_;
+
+ /// @brief Prefix Kea should use when generating domain-names.
+ util::Optional<std::string> ddns_generated_prefix_;
+
+ /// @brief Suffix Kea should use when to qualify partial domain-names.
+ util::Optional<std::string> ddns_qualifying_suffix_;
+
+ /// @brief Should Kea perform updates when leases are extended
+ util::Optional<bool> ddns_update_on_renew_;
+
+ /// @brief DDNS conflict resolution mode
+ util::Optional<std::string> ddns_conflict_resolution_mode_;
+
+ /// @brief Percentage of the lease lifetime to use for DNS TTL.
+ util::Optional<double> ddns_ttl_percent_;
+
+ /// @brief Explicit value to use for DNS TTL.
+ util::Optional<uint32_t> ddns_ttl_;
+
+ /// @brief Minimum value to use for DNS TTL.
+ util::Optional<uint32_t> ddns_ttl_min_;
+
+ /// @brief Maximum value to use for DNS TTL.
+ util::Optional<uint32_t> ddns_ttl_max_;
+
+ /// @brief Regular expression describing invalid characters for client
+ /// hostnames.
+ util::Optional<std::string> hostname_char_set_;
+
+ /// @brief A string to replace invalid characters when scrubbing hostnames.
+ /// Meaningful only if hostname_char_set_ is not empty.
+ util::Optional<std::string> hostname_char_replacement_;
};
class Pool4;
return (false);
}
+ if (pool_) {
+ auto optional = pool_->getDdnsSendUpdates();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (d2_client_enabled_ && subnet_->getDdnsSendUpdates().get());
}
return (false);
}
+ if (pool_) {
+ auto optional = pool_->getDdnsOverrideNoUpdate();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsOverrideNoUpdate().get());
}
return (false);
}
+ if (pool_) {
+ auto optional = pool_->getDdnsOverrideClientUpdate();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsOverrideClientUpdate().get());
}
return (D2ClientConfig::RCM_NEVER);
}
+ if (pool_) {
+ auto optional = pool_->getDdnsReplaceClientNameMode();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsReplaceClientNameMode().get());
}
return ("");
}
+ if (pool_) {
+ auto optional = pool_->getDdnsGeneratedPrefix();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsGeneratedPrefix().get());
}
return ("");
}
+ if (pool_) {
+ auto optional = pool_->getDdnsQualifyingSuffix();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsQualifyingSuffix().get());
}
return (false);
}
+ if (pool_) {
+ auto optional = pool_->getDdnsUpdateOnRenew();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsUpdateOnRenew().get());
}
+std::string
+DdnsParams::getConflictResolutionMode() const {
+ if (!subnet_) {
+ return ("check-with-dhcid");
+ }
+
+ if (pool_) {
+ auto optional = pool_->getDdnsConflictResolutionMode();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
+ return (subnet_->getDdnsConflictResolutionMode().get());
+}
+
+
util::Optional<double>
DdnsParams::getTtlPercent() const {
if (!subnet_) {
return (util::Optional<double>());
}
+ if (pool_) {
+ auto optional = pool_->getDdnsTtlPercent();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsTtlPercent());
}
return (util::Optional<uint32_t>());
}
+ if (pool_) {
+ auto optional = pool_->getDdnsTtl();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsTtl());
}
return (util::Optional<uint32_t>());
}
+ if (pool_) {
+ auto optional = pool_->getDdnsTtlMin();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsTtlMin());
}
return (util::Optional<uint32_t>());
}
+ if (pool_) {
+ auto optional = pool_->getDdnsTtlMax();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
return (subnet_->getDdnsTtlMax());
}
-std::string
-DdnsParams::getConflictResolutionMode() const {
+PoolPtr
+DdnsParams::setPoolFromAddress(const asiolink::IOAddress& address) {
if (!subnet_) {
- return ("check-with-dhcid");
+ /// @todo Not sure this can happen.
+ isc_throw(InvalidOperation,
+ "DdnsParams::setPoolFromAddress called without a subnet");
}
- return (subnet_->getDdnsConflictResolutionMode().get());
+ pool_ = subnet_->getPool((address.isV4() ? Lease::TYPE_V4 : Lease::TYPE_NA), address, false);
+ return (pool_);
}
+
} // namespace dhcp
} // namespace isc
/// @brief Default constructor
DdnsParams() : subnet_(), d2_client_enabled_(false) {}
- /// @brief Constructor for DHCPv4 subnets
+ /// @brief Constructor
///
- /// @param subnet Pointer to Subnet4 instance to use for fetching
+ /// @param subnet Pointer to subnet instance to use for fetching
/// parameter values (typically this is the selected subnet).
/// @param d2_client_enabled flag which indicates whether or not
/// D2Client is enabled (typically the value should come from
/// global D2Client configuration).
- DdnsParams(const ConstSubnet4Ptr& subnet, bool d2_client_enabled)
- : subnet_(boost::dynamic_pointer_cast<const Subnet>(subnet)),
- d2_client_enabled_(d2_client_enabled) {}
-
- /// @brief Constructor for DHCPv6 subnets
- ///
- /// @param subnet Pointer to Subnet6 instance to use for fetching
- /// parameter values (typically this is the selected subnet).
- /// @param d2_client_enabled flag which indicates whether or not
- /// D2Client is enabled (typically the value should come from
- /// global D2Client configuration).
- DdnsParams(const ConstSubnet6Ptr& subnet, bool d2_client_enabled)
- : subnet_(boost::dynamic_pointer_cast<const Subnet>(subnet)),
+ DdnsParams(const ConstSubnetPtr& subnet, bool d2_client_enabled)
+ : subnet_(subnet),
d2_client_enabled_(d2_client_enabled) {}
/// @brief Returns whether or not DHCP DDNS updating is enabled.
}
}
+ PoolPtr setPoolFromAddress(const asiolink::IOAddress& address);
+
+ void resetPool() {
+ pool_.reset();
+ }
+
+ PoolPtr getPool() const {
+ return (pool_);
+ }
+
private:
/// @brief Subnet from which values should be fetched.
ConstSubnetPtr subnet_;
/// @brief Flag indicating whether or not the D2Client is enabled.
bool d2_client_enabled_;
+
+ /// @brief Pool within the subnet from which values should be fetched.
+ PoolPtr pool_;
};
/// @brief Defines a pointer for DdnsParams instances.
namespace {
+/// @brief Class for testing pools.
+class PoolTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ PoolTest() = default;
+
+ /// @brief Destructor
+ virtual ~PoolTest() = default;
+
+ /// @brief Verifies the DDNS parameter accessors and the
+ /// hasDdnsParameters() method.
+ ///
+ /// @param family sets the protocol to be used AF_INET or AF_INET6.
+ void checkDdnsParamters(uint16_t family) {
+ PoolPtr pool;
+ if (family == AF_INET) {
+ pool.reset(new Pool4(IOAddress("192.0.2.0"), 25));
+ } else {
+ pool.reset(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8::1"),
+ IOAddress("2001:db8::2")));
+ }
+
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ util::Optional<bool> bool_unspec;
+ util::Optional<bool> bool_spec(true);
+
+ pool->setDdnsSendUpdates(bool_spec);
+ EXPECT_EQ(pool->getDdnsSendUpdates(), bool_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsSendUpdates(bool_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsOverrideNoUpdate(bool_spec);
+ EXPECT_EQ(pool->getDdnsOverrideNoUpdate(), bool_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsOverrideNoUpdate(bool_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsOverrideClientUpdate(bool_spec);
+ EXPECT_EQ(pool->getDdnsOverrideClientUpdate(), bool_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsOverrideClientUpdate(bool_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ util::Optional<D2ClientConfig::ReplaceClientNameMode> mode_unspec;
+ util::Optional<D2ClientConfig::ReplaceClientNameMode>
+ mode_spec(D2ClientConfig::RCM_WHEN_PRESENT);
+
+ pool->setDdnsReplaceClientNameMode(mode_spec);
+ EXPECT_EQ(pool->getDdnsReplaceClientNameMode(), mode_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsReplaceClientNameMode(mode_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ util::Optional<std::string> string_unspec;
+ util::Optional<std::string> string_spec("some_string");
+
+ pool->setDdnsGeneratedPrefix(string_spec);
+ EXPECT_EQ(pool->getDdnsGeneratedPrefix(), string_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsGeneratedPrefix(string_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsQualifyingSuffix(string_spec);
+ EXPECT_EQ(pool->getDdnsQualifyingSuffix(), string_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsQualifyingSuffix(string_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsUpdateOnRenew(bool_spec);
+ EXPECT_EQ(pool->getDdnsUpdateOnRenew(), bool_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsUpdateOnRenew(bool_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsConflictResolutionMode(string_spec);
+ EXPECT_EQ(pool->getDdnsConflictResolutionMode(), string_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsConflictResolutionMode(string_unspec);
+
+ util::Optional<double> double_unspec;
+ util::Optional<double> double_spec(0.5);
+
+ pool->setDdnsTtlPercent(double_spec);
+ EXPECT_EQ(pool->getDdnsTtlPercent(), double_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsTtlPercent(double_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ util::Optional<uint32_t> int_unspec;
+ util::Optional<uint32_t> int_spec(750);
+
+ pool->setDdnsTtl(int_spec);
+ EXPECT_EQ(pool->getDdnsTtl(), int_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsTtl(int_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsTtlMin(int_spec);
+ EXPECT_EQ(pool->getDdnsTtlMin(), int_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsTtlMin(int_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setDdnsTtlMax(int_spec);
+ EXPECT_EQ(pool->getDdnsTtlMax(), int_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setDdnsTtlMax(int_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setHostnameCharSet(string_spec);
+ EXPECT_EQ(pool->getHostnameCharSet(), string_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setHostnameCharSet(string_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+
+ pool->setHostnameCharReplacement(string_spec);
+ EXPECT_EQ(pool->getHostnameCharReplacement(), string_spec);
+ EXPECT_TRUE(pool->hasDdnsParameters());
+ pool->setHostnameCharReplacement(string_unspec);
+ EXPECT_FALSE(pool->hasDdnsParameters());
+ }
+};
+
TEST(Pool4Test, constructorFirstLast) {
// let's construct 192.0.2.1-192.0.2.255 pool
" \"pool-id\": 5 "
"}";
isc::test::runToElementTest<Pool4>(expected3, pool3);
+
+ pool3.setDdnsSendUpdates(true);
+ pool3.setDdnsOverrideNoUpdate(true);
+ pool3.setDdnsOverrideClientUpdate(true);
+ pool3.setDdnsReplaceClientNameMode(D2ClientConfig::RCM_NEVER);
+ pool3.setDdnsGeneratedPrefix("prefix");
+ pool3.setDdnsQualifyingSuffix("example.com.");
+ pool3.setDdnsUpdateOnRenew(false);
+ pool3.setDdnsConflictResolutionMode("check-without-dhcid");
+ pool3.setDdnsTtlPercent(0.85);
+ pool3.setDdnsTtl(400);
+ pool3.setDdnsTtlMin(150);
+ pool3.setDdnsTtlMax(650);
+ pool3.setHostnameCharReplacement("x");
+ pool3.setHostnameCharSet("[^A-Z]");
+
+ std::string expected4 = R"(
+ {
+ "pool": "192.0.2.0/25",
+ "option-data": [ ],
+ "pool-id": 5,
+ "ddns-send-updates": true,
+ "ddns-override-no-update": true,
+ "ddns-override-client-update": true,
+ "ddns-replace-client-name": "never",
+ "ddns-generated-prefix": "prefix",
+ "ddns-qualifying-suffix": "example.com.",
+ "ddns-update-on-renew": false,
+ "ddns-conflict-resolution-mode": "check-without-dhcid",
+ "ddns-ttl": 400,
+ "ddns-ttl-max": 650,
+ "ddns-ttl-min": 150,
+ "ddns-ttl-percent": 0.85,
+ "hostname-char-replacement": "x",
+ "hostname-char-set": "[^A-Z]"
+ })";
+
+ isc::test::runToElementTest<Pool4>(expected4, pool3);
+
}
// This test checks that it is possible to specify pool specific options.
EXPECT_TRUE(pool.getAdditionalClasses().contains("foo"));
}
+TEST_F(PoolTest, ddnsParameters4) {
+ checkDdnsParamters(AF_INET);
+}
+
+TEST_F(PoolTest, ddnsParameters6) {
+ checkDdnsParamters(AF_INET6);
+}
+
} // end of anonymous namespace
}
}
+/// @brief Class for DdnsParams class.
+class DdnsParamsTest : public testing::Test {
+public:
+ /// @brief Constructor
+ DdnsParamsTest() = default;
+
+ /// @brief Destructor
+ virtual ~DdnsParamsTest() = default;
+
+ /// @brief Verifies that the DdnsParams accessors return parameter values
+ /// from the proper source.
+ ///
+ /// @param subnet Subnet under test.
+ /// @param address Address to locate the pool within the subnet via
+ /// DdnsParams::setPoolFromAddress().
+ /// @param expected_pool expected Pool returned by setPoolFromAddress().
+ void checkDdnsParameters(SubnetPtr subnet, IOAddress address, PoolPtr expected_pool) {
+ // Create DdnsParams instance with the subnet.
+ DdnsParamsPtr params(new DdnsParams(subnet, true));
+
+ // Attempt to locate the pool based on the given address.
+ PoolPtr pool = params->setPoolFromAddress(address);
+
+ if (!expected_pool) {
+ // Pool should not have been found.
+ ASSERT_FALSE(pool);
+ } else {
+ // Pool should have been found.
+ ASSERT_TRUE(pool);
+ }
+
+ // Verify each of the parameters comes from the expected source, either
+ // the subnet or the pool.
+ if (pool && !(pool->getDdnsSendUpdates().unspecified())) {
+ EXPECT_EQ(params->getEnableUpdates(), pool->getDdnsSendUpdates().get());
+ } else {
+ EXPECT_EQ(params->getEnableUpdates(), subnet->getDdnsSendUpdates().get());
+ }
+
+ if (pool && !(pool->getDdnsOverrideNoUpdate().unspecified())) {
+ EXPECT_EQ(params->getOverrideNoUpdate(), pool->getDdnsOverrideNoUpdate().get());
+ } else {
+ EXPECT_EQ(params->getOverrideNoUpdate(), subnet->getDdnsOverrideNoUpdate().get());
+ }
+
+ if (pool && !(pool->getDdnsOverrideClientUpdate().unspecified())) {
+ EXPECT_EQ(params->getOverrideClientUpdate(), pool->getDdnsOverrideClientUpdate().get());
+ } else {
+ EXPECT_EQ(params->getOverrideClientUpdate(), subnet->getDdnsOverrideClientUpdate().get());
+ }
+
+ if (pool && !(pool->getDdnsReplaceClientNameMode().unspecified())) {
+ EXPECT_EQ(params->getReplaceClientNameMode(), pool->getDdnsReplaceClientNameMode().get());
+ } else {
+ EXPECT_EQ(params->getReplaceClientNameMode(), subnet->getDdnsReplaceClientNameMode().get());
+ }
+
+ if (pool && !(pool->getDdnsGeneratedPrefix().unspecified())) {
+ EXPECT_EQ(params->getGeneratedPrefix(), pool->getDdnsGeneratedPrefix().get());
+ } else {
+ EXPECT_EQ(params->getGeneratedPrefix(), subnet->getDdnsGeneratedPrefix().get());
+ }
+
+ if (pool && !(pool->getDdnsQualifyingSuffix().unspecified())) {
+ EXPECT_EQ(params->getQualifyingSuffix(), pool->getDdnsQualifyingSuffix().get());
+ } else {
+ EXPECT_EQ(params->getQualifyingSuffix(), subnet->getDdnsQualifyingSuffix().get());
+ }
+
+ if (pool && !(pool->getDdnsUpdateOnRenew().unspecified())) {
+ EXPECT_EQ(params->getUpdateOnRenew(), pool->getDdnsUpdateOnRenew().get());
+ } else {
+ EXPECT_EQ(params->getUpdateOnRenew(), subnet->getDdnsUpdateOnRenew().get());
+ }
+
+ if (pool && !(pool->getDdnsConflictResolutionMode().unspecified())) {
+ EXPECT_EQ(params->getConflictResolutionMode(), pool->getDdnsConflictResolutionMode().get());
+ } else {
+ EXPECT_EQ(params->getConflictResolutionMode(), subnet->getDdnsConflictResolutionMode().get());
+ }
+
+ if (pool && !(pool->getDdnsTtlPercent().unspecified())) {
+ EXPECT_EQ(params->getTtlPercent(), pool->getDdnsTtlPercent().get());
+ } else {
+ EXPECT_EQ(params->getTtlPercent(), subnet->getDdnsTtlPercent().get());
+ }
+
+ if (pool && !(pool->getDdnsTtl().unspecified())) {
+ EXPECT_EQ(params->getTtl(), pool->getDdnsTtl().get());
+ } else {
+ EXPECT_EQ(params->getTtl(), subnet->getDdnsTtl().get());
+ }
+
+ if (pool && !(pool->getDdnsTtlMin().unspecified())) {
+ EXPECT_EQ(params->getTtlMin(), pool->getDdnsTtlMin().get());
+ } else {
+ EXPECT_EQ(params->getTtlMin(), subnet->getDdnsTtlMin().get());
+ }
+
+ if (pool && !(pool->getDdnsTtlMax().unspecified())) {
+ EXPECT_EQ(params->getTtlMax(), pool->getDdnsTtlMax().get());
+ } else {
+ EXPECT_EQ(params->getTtlMax(), subnet->getDdnsTtlMax().get());
+ }
+ }
+};
+
+TEST_F(DdnsParamsTest, checkDdnsParameters4) {
+ // Create a subnet.
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 10));
+
+ // Set values in the subnet for each of the DDNS parameters.
+ subnet->setDdnsSendUpdates(false);
+ subnet->setDdnsOverrideNoUpdate(true);
+ subnet->setDdnsOverrideClientUpdate(true);
+ subnet->setDdnsReplaceClientNameMode(D2ClientConfig::RCM_ALWAYS);
+ subnet->setDdnsGeneratedPrefix("sn_prefix");
+ subnet->setDdnsQualifyingSuffix("sn_suffix");
+ subnet->setDdnsUpdateOnRenew(true);
+ subnet->setDdnsConflictResolutionMode("check-with-dhcid");
+ subnet->setDdnsTtlPercent(0.75);
+ subnet->setDdnsTtl(500);
+ subnet->setDdnsTtlMin(250);
+ subnet->setDdnsTtlMax(750);
+ subnet->setHostnameCharReplacement("X");
+ subnet->setHostnameCharSet("[^A-Z]");
+
+ // Create a pool and add it to the subnet.
+ Pool4Ptr pool(new Pool4(IOAddress("192.0.2.1"), IOAddress("192.0.2.100")));
+ ASSERT_NO_THROW(subnet->addPool(pool));
+
+ {
+ // Values all come from subnet, address not in pool.
+ SCOPED_TRACE("Address not in pool");
+ checkDdnsParameters(subnet, IOAddress("192.0.2.200"), Pool4Ptr());
+ }
+
+ {
+ // Values all come from subnet, address in pool but pool specifies no values.
+ SCOPED_TRACE("Pool exists but specifies none");
+ checkDdnsParameters(subnet, IOAddress("192.0.2.50"), pool);
+ }
+
+ // Set values in the pool for each of the DDNS parameters.
+ pool->setDdnsSendUpdates(true);
+ pool->setDdnsOverrideNoUpdate(false);
+ pool->setDdnsOverrideClientUpdate(false);
+ pool->setDdnsReplaceClientNameMode(D2ClientConfig::RCM_NEVER);
+ pool->setDdnsGeneratedPrefix("pl_prefix");
+ pool->setDdnsQualifyingSuffix("pl_suffix");
+ pool->setDdnsUpdateOnRenew(false);
+ pool->setDdnsConflictResolutionMode("check-without-dhcid");
+ pool->setDdnsTtlPercent(0.85);
+ pool->setDdnsTtl(400);
+ pool->setDdnsTtlMin(150);
+ pool->setDdnsTtlMax(650);
+ pool->setHostnameCharReplacement("y");
+ pool->setHostnameCharSet("[^a-z]");
+
+ {
+ // Values all come from pool.
+ SCOPED_TRACE("Pool specifies all");
+ checkDdnsParameters(subnet, IOAddress("192.0.2.50"), pool);
+ }
+}
+
+TEST_F(DdnsParamsTest, checkDdnsParameters6) {
+ // Create a subnet.
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64,
+ 1, 2, 3, 4, SubnetID(1)));
+
+ // Set values in the subnet for each of the DDNS parameters.
+ subnet->setDdnsSendUpdates(false);
+ subnet->setDdnsOverrideNoUpdate(true);
+ subnet->setDdnsOverrideClientUpdate(true);
+ subnet->setDdnsReplaceClientNameMode(D2ClientConfig::RCM_ALWAYS);
+ subnet->setDdnsGeneratedPrefix("sn_prefix");
+ subnet->setDdnsQualifyingSuffix("sn_suffix");
+ subnet->setDdnsUpdateOnRenew(true);
+ subnet->setDdnsConflictResolutionMode("check-with-dhcid");
+ subnet->setDdnsTtlPercent(0.75);
+ subnet->setDdnsTtl(500);
+ subnet->setDdnsTtlMin(250);
+ subnet->setDdnsTtlMax(750);
+ subnet->setHostnameCharReplacement("X");
+ subnet->setHostnameCharSet("[^A-Z]");
+
+ // Create a pool and add it to the subnet.
+ Pool6Ptr pool(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::100")));
+ ASSERT_NO_THROW(subnet->addPool(pool));
+
+ {
+ // Values all come from subnet, address not in pool.
+ SCOPED_TRACE("Address not in pool");
+ checkDdnsParameters(subnet, IOAddress("2001:db8:1::200"), Pool6Ptr());
+ }
+
+ {
+ // Values all come from subnet, address in pool but pool specifies no values.
+ SCOPED_TRACE("Pool exists but specifies none");
+ checkDdnsParameters(subnet, IOAddress("2001:db8:1::10"), pool);
+ }
+
+ // Set values in the pool for each of the DDNS parameters.
+ pool->setDdnsSendUpdates(true);
+ pool->setDdnsOverrideNoUpdate(false);
+ pool->setDdnsOverrideClientUpdate(false);
+ pool->setDdnsReplaceClientNameMode(D2ClientConfig::RCM_NEVER);
+ pool->setDdnsGeneratedPrefix("pl_prefix");
+ pool->setDdnsQualifyingSuffix("pl_suffix");
+ pool->setDdnsUpdateOnRenew(false);
+ pool->setDdnsConflictResolutionMode("check-without-dhcid");
+ pool->setDdnsTtlPercent(0.85);
+ pool->setDdnsTtl(400);
+ pool->setDdnsTtlMin(150);
+ pool->setDdnsTtlMax(650);
+ pool->setHostnameCharReplacement("y");
+ pool->setHostnameCharSet("[^a-z]");
+
+ {
+ // Values all come from pool.
+ SCOPED_TRACE("Pool specifies all");
+ checkDdnsParameters(subnet, IOAddress("2001:db8:1::10"), pool);
+ }
+}
+
} // end of anonymous namespace