TEST_F(NameDhcpv4SrvTest, poolDdnsParametersTest) {
// A configuration with following pools:
// 1. Specifies a qualifying suffix
- // 2. Specifes no DDNS parameters
+ // 2. Specifies no DDNS parameters
// 3. Disables DDNS updates
// 4. Specifies a qualifying suffix but disables DDNS updates
std::string config = R"(
}
}
- // Check if the subnet was dynamnically changed by the allocation engine.
+ // Check if the subnet was dynamically changed by the allocation engine.
if (ctx.subnet_ && orig_subnet && (orig_subnet->getID() != ctx.subnet_->getID())) {
- // We get the network for logging only. It should always be set as this a dynamic
- // change should only happen within shared-networks. Not having one might not be
- // an error if a hook changed the subnet?
+ // We get the network for logging only. It should always be set as
+ // this a dynamic change should only happen within shared-networks.
+ // Not having one might not be an error if a hook changed the subnet?
SharedNetwork6Ptr network;
orig_subnet->getSharedNetwork(network);
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_SUBNET_DYNAMICALLY_CHANGED)
///
/// Updates the context DDNS parameters to include those from the pool
/// associated with the first active NA lease address and then checks
- /// to see if the subnet has been dynamicaly changed. If either the
+ /// to see if the subnet has been dynamically changed. If either the
/// pool has DDNS parameters or the subnet has changed the FQDN and
/// DDNS flags are recalculated in the event the pool or subnet change
/// introduced different parameter values otherwise the function returns.
///
/// @param iaid IAID
/// @param pkt A DHCPv6 message to which the IA option should be added.
- /// @param cxt allocation engine context to which IA option should be
- /// added.
+ /// @param cxt allocation engine context to which IA option should be
+ /// added.
void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt,
AllocEngine::ClientContext6& ctx) {
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
/// @param iaid IAID
/// @param status_code Status code
/// @param pkt A DHCPv6 message to which the option should be added.
- /// @param cxt allocation engine context to which IA option should be
- /// added.
+ /// @param cxt allocation engine context to which IA option should be
+ /// added.
void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt,
AllocEngine::ClientContext6& ctx) {
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
ASSERT_TRUE(pool);
}
- /// @brief Verifies that DDNS TTL parameters are used when specified.
+ /// @brief Verifies that DDNS TTL parameters are used when specified.
///
/// @param valid_flt lease life time
/// @param ddns_ttl_percent expected configured value for ddns-ttl-percent
// Create an IA.
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, 1234, 1500, 3000);
- Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR,
+ Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR,
IOAddress("2001:db8:1::1"),
valid_lft, valid_lft));
opt_ia->addOption(opt_iaaddr);
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
999, // ttl
- Optional<uint32_t>(), // min
+ Optional<uint32_t>(), // min
Optional<uint32_t>()); // max
}
TEST_F(FqdnDhcpv6SrvTest, ddnsTtlMinTest) {
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
- Optional<uint32_t>(), // ttl
+ Optional<uint32_t>(), // ttl
800, // ttl-min
Optional<uint32_t>()); // ttl-max
}
TEST_F(FqdnDhcpv6SrvTest, ddnsTtlMaxTest) {
testDdnsTtlParameters(2100, // valid lft
Optional<double>(), // percent
- Optional<uint32_t>(), // ttl
+ Optional<uint32_t>(), // ttl
Optional<uint32_t>(), // ttl-min
- 500); // ttl-max
+ 500); // ttl-max
}
-// Verify pool-level DDNS pararmeters are used.
+// Verify pool-level DDNS parameters are used.
// We don't verify all of them, just enough
// enough to ensure proper scoping of values.
TEST_F(FqdnDhcpv6SrvTest, poolDdnsParametersTest) {
// A configuration with following pools:
// 1. Specifies a qualifying suffix
- // 2. Specifes no DDNS parameters
+ // 2. Specifies no DDNS parameters
// 3. Disables DDNS updates
// 4. Specifies a qualifying suffix but disables DDNS updates
std::string config = R"(
query->setIndex(ETH0_INDEX);
// Add the client id.
- OptionPtr client_id(new Option(Option::V6, D6O_CLIENTID, scenario.raw_duid_));
+ OptionPtr client_id(new Option(Option::V6, D6O_CLIENTID,
+ scenario.raw_duid_));
query->addOption(client_id);
query->addOption(srv_->getServerID());
// Add an IA requesting the expected address.
Option6IAPtr ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
- OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, scenario.expected_address_, 300, 500));
+ OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR,
+ scenario.expected_address_,
+ 300, 500));
ia->addOption(hint_opt);
query->addOption(ia);
- // Add an FQDN option. We set it to partial to ensure we qualify it with a suffix.
- query->addOption(createClientFqdn(Option6ClientFqdn::FLAG_S, scenario.client_fqdn_,
+ // Add an FQDN option. We set it to partial to ensure we qualify
+ // it with a suffix.
+ query->addOption(createClientFqdn(Option6ClientFqdn::FLAG_S,
+ scenario.client_fqdn_,
Option6ClientFqdn::PARTIAL));
// Process the REQUEST.
// Check that we got the address we requested.
tmp = ia->getOption(D6O_IAADDR);
- boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
+ boost::shared_ptr<Option6IAAddr> addr
+ = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
ASSERT_TRUE(addr);
EXPECT_EQ(addr->getAddress(), scenario.expected_address_);
// Check that the lease exists with the correct FDQN.
- Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr->getAddress());
+ Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr->getAddress());
ASSERT_TRUE(lease);
EXPECT_EQ(lease->hostname_, scenario.expected_fqdn_);
- // Verfiy the FQDN in the response is correct.
+ // Verify the FQDN in the response is correct.
Option6ClientFqdnPtr fqdn;
ASSERT_TRUE(fqdn = boost::dynamic_pointer_cast<
Option6ClientFqdn>(reply->getOption(D6O_CLIENT_FQDN)));
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
scenario.expected_address_.toText(),
scenario.expected_dhcid_,
- 0, 4000,
+ 0, 4000,
scenario.expected_fqdn_);
}
}
libkea_dhcpsrv_la_SOURCES += tracking_lease_mgr.cc tracking_lease_mgr.h
libkea_dhcpsrv_la_SOURCES += utils.h
libkea_dhcpsrv_la_SOURCES += writable_host_data_source.h
+libkea_dhcpsrv_la_SOURCES += ddns_params.cc ddns_params.h
# Configuration parsers
libkea_dhcpsrv_la_SOURCES += parsers/base_network_parser.cc
subnet_selector.h \
timer_mgr.h \
utils.h \
- writable_host_data_source.h
+ writable_host_data_source.h \
+ ddns_params.h
if FUZZING
libkea_dhcpsrv_include_HEADERS += \
isc_throw(BadValue, "internal error: CfgHostsList::internalize: "
"no reservations for subnet ID " << subnet_id);
}
- map_.insert(std::make_pair(subnet_id,
+ map_.insert(std::make_pair(subnet_id,
boost::const_pointer_cast<Element>(resvs)));
}
}
- <b>address</b> - IPv4 address \n
type: string \n
- example: 192.0.2.1
+ example: 192.0.2.1
- - <b>hwaddr</b> - hardware address (without the hardware type) \n
- type: string \n
+ - <b>hwaddr</b> - hardware address (without the hardware type) \n
+ type: string \n
example: 00:01:02:03:04:05
-
- - <b>client_id</b> - client identifier \n
+
+ - <b>client_id</b> - client identifier \n
type: string \n
example: 01:02:03:03:04:aa:bb:cc
- <b>valid_lifetime</b> - valid lifetime \n
- type: uint32_t \n
+ type: uint32_t \n
example: 200
- <b>expire</b> - expiration date \n
type: uint64_t (cltt + valid lifetime) \n
example: 1733517739
- - <b>subnet_id</b> - DHCPv4 subnet identifier \n
- type: int32_t (0 and max excluded) \n
+ - <b>subnet_id</b> - DHCPv4 subnet identifier \n
+ type: int32_t (0 and max excluded) \n
example: 1
- <b>fqdn_fwd</b> - FQDN forward DNS RR update flag \n
- <b>hostname</b> - hostname \n
type: string (separators are escaped) \n
example: foo.bar
-
+
- <b>state</b> - lease state \n
type: int32_t (0 = assigned, 1 = declined, 2 = expired-reclaimed, 3 = released) \n
example: 0
- <b>user_context</b> - user context \n
- type: string (separators are escaped) \n
+ type: string (separators are escaped) \n
example: <tt>{ \"foo\": true }</tt>
- - <b>pool_id</b> - pool identifier \n
- type: uint32_t \n
+ - <b>pool_id</b> - pool identifier \n
+ type: uint32_t \n
example: 0
for instance:
example: <tt>{ \"foo\": true }</tt>
- <b>hwtype</b> - hardware type \n
- type: uint16_t (can be empty/omitted) \n
+ type: uint16_t (can be empty/omitted) \n
example: 1
- <b>hwaddr_source</b> - source of hardware address and type \n
- tyoe: uint32_t (one bit from an 8 bit mask, can be empty/omitted) \n
+ tyoe: uint32_t (one bit from an 8 bit mask, can be empty/omitted) \n
example: 0
- <b>pool_id</b> - pool identifier \n
\verbatim
2001:db8::1,00:01:02:03:04:05:06:0f,200,800,8,100,0,7,128,1,1,,,1,{ \"foo\": true },,,0\n
\endverbatim
-
+
More examples can be found in unit tests.
@section dhcpdb-host Host Backends
--- /dev/null
+// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/ddns_params.h>
+
+namespace isc {
+namespace dhcp {
+
+bool
+DdnsParams::getUpdateOnRenew() const {
+ if (!subnet_) {
+ 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());
+}
+
+util::Optional<uint32_t>
+DdnsParams::getTtl() const {
+ if (!subnet_) {
+ return (util::Optional<uint32_t>());
+ }
+
+ if (pool_) {
+ auto optional = pool_->getDdnsTtl();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
+ return (subnet_->getDdnsTtl());
+}
+
+util::Optional<uint32_t>
+DdnsParams::getTtlMin() const {
+ if (!subnet_) {
+ return (util::Optional<uint32_t>());
+ }
+
+ if (pool_) {
+ auto optional = pool_->getDdnsTtlMin();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
+ return (subnet_->getDdnsTtlMin());
+}
+
+util::Optional<uint32_t>
+DdnsParams::getTtlMax() const {
+ if (!subnet_) {
+ return (util::Optional<uint32_t>());
+ }
+
+ if (pool_) {
+ auto optional = pool_->getDdnsTtlMax();
+ if (!optional.unspecified()) {
+ return (optional.get());
+ }
+ }
+
+ return (subnet_->getDdnsTtlMax());
+}
+
+PoolPtr
+DdnsParams::setPoolFromAddress(const asiolink::IOAddress& address) {
+ if (!subnet_) {
+ /// @todo Not sure this can happen.
+ isc_throw(InvalidOperation,
+ "DdnsParams::setPoolFromAddress called without a subnet");
+ }
+
+ pool_ = subnet_->getPool((address.isV4() ? Lease::TYPE_V4 : Lease::TYPE_NA),
+ address, false);
+ return (pool_);
+}
+
+} // namespace dhcp
+} // namespace isc
--- /dev/null
+// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef DDNS_PARAMS_H
+#define DDNS_PARAMS_H
+
+#include <cc/data.h>
+#include <dhcpsrv/subnet.h>
+#include <util/optional.h>
+#include <util/str.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Convenience container for conveying DDNS behavioral parameters
+/// It is intended to be created per Packet exchange using the selected
+/// subnet passed into functions that require them
+class DdnsParams {
+public:
+ /// @brief Default constructor
+ DdnsParams() : subnet_(), d2_client_enabled_(false) {}
+
+ /// @brief Constructor
+ ///
+ /// @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 ConstSubnetPtr& subnet, bool d2_client_enabled)
+ : subnet_(subnet),
+ d2_client_enabled_(d2_client_enabled) {}
+
+ /// @brief Returns whether or not DHCP DDNS updating is enabled.
+ /// The value is the logical AND of d2_client_enabled_ and
+ /// the value returned by subnet_'s getDdnsSendUpdates().
+ ///
+ /// @return True if updates are enabled, false otherwise or if
+ /// subnet_ is empty.
+ bool getEnableUpdates() const;
+
+ /// @brief Returns whether or not Kea should perform updates, even if
+ /// client requested no updates.
+ ///
+ /// @return The value from the subnet_ or false if subnet_ is empty.
+ bool getOverrideNoUpdate() const;
+
+ /// @brief Returns whether or not Kea should perform updates, even if
+ /// client requested delegation.
+ ///
+ /// @return The value from the subnet_ or false if subnet_ is empty.
+ bool getOverrideClientUpdate() const;
+
+ /// @brief Returns how Kea should handle the domain-name supplied by
+ /// the client.
+ ///
+ /// @return The value from the subnet_ or RCM_NEVER if subnet_ is empty.
+ D2ClientConfig::ReplaceClientNameMode getReplaceClientNameMode() const;
+
+ /// @brief Returns the Prefix Kea should use when generating domain-names.
+ ///
+ /// @return The value from the subnet_ or an empty string if subnet_ is empty.
+ std::string getGeneratedPrefix() const;
+
+ /// @brief Returns the suffix Kea should use when to qualify partial
+ /// domain-names.
+ ///
+ /// @return The value from the subnet_ or an empty string if subnet_ is empty.
+ std::string getQualifyingSuffix() const;
+
+ /// @brief Returns the regular expression describing invalid characters
+ /// for client hostnames. If empty, host name scrubbing should not be done.
+ ///
+ /// @return The value from the subnet_ or an empty string if subnet_ is empty.
+ std::string getHostnameCharSet() const;
+
+ /// @brief Returns the string to replace invalid characters when scrubbing
+ /// hostnames. Meaningful only if hostname_char_set_ is not empty.
+ ///
+ /// @return The value from the subnet_ or an empty string if subnet_ is empty.
+ std::string getHostnameCharReplacement() const;
+
+ /// @brief Returns a regular expression string sanitizer
+ ///
+ /// If the value returned by getHostnameCharSet() is not empty, then it is
+ /// used in conjunction the value returned by getHostnameCharReplacment()
+ /// (which may be empty) to create and return a StringSanitizer instance.
+ /// Otherwise it will return an empty pointer.
+ ///
+ /// @return pointer to the StringSanitizer instance or an empty pointer
+ /// @throw BadValue if the compilation fails.
+ isc::util::str::StringSanitizerPtr getHostnameSanitizer() const;
+
+ /// @brief Returns whether or not DNS should be updated when leases renew.
+ ///
+ /// If this is true, DNS should always be updated when leases are
+ /// extended (i.e. renewed/rebound) even if the DNS information
+ /// has not changed.
+ ///
+ /// @return True if updates should always be performed.
+ bool getUpdateOnRenew() const;
+
+ /// @brief Returns percent of lease lifetime to use for TTL
+ ///
+ /// This value, if greater than zero, is used to calculate the lease lifetime
+ /// passed to D2 in the NCR. Otherwise the value is calculated per RFC 4702.
+ ///
+ /// @return TTL percent as an Optional.
+ util::Optional<double> getTtlPercent() const;
+
+ /// @brief Returns explicit TTL to use
+ ///
+ /// This value, if greater than zero, is used as the lifetime
+ /// passed to D2 in the NCR.
+ ///
+ /// @return TTL as an Optional.
+ util::Optional<uint32_t> getTtl() const;
+
+ /// @brief Returns the minimum TTL to use
+ ///
+ /// This value, if greater than zero, is used as the lower boundary
+ /// for calculated TTLs.
+ ///
+ /// @return TTL minimum as an Optional.
+ util::Optional<uint32_t> getTtlMin() const;
+
+ /// @brief Returns the maximum TTL to use
+ ///
+ /// This value, if greater than zero, is used as the upper boundary
+ /// for calculated TTLs.
+ ///
+ /// @return TTL maximum as an Optional.
+ util::Optional<uint32_t> getTtlMax() const;
+
+ /// @brief Returns the DDNS config resolution mode for kea-dhcp-ddns
+ ///
+ /// This value is communicated to D2 via the NCR.
+ ///
+ /// @return the DDNS conflict resolution mode
+ std::string getConflictResolutionMode() const;
+
+ /// @brief Returns the subnet-id of the subnet associated with these parameters
+ ///
+ /// @return value of subnet-id (or 0 if no subnet is associated)
+ SubnetID getSubnetId() const {
+ if (subnet_) {
+ return (subnet_->getID());
+ } else {
+ return (0);
+ }
+ }
+
+ /// @brief Sets the pool based on the current subnet and given address
+ ///
+ /// @param address lease address for which the pool is desired.
+ /// @return a pointer to the newly set current pool or an
+ /// empty pointer if there is either no subnet or no matching
+ /// pool.
+ PoolPtr setPoolFromAddress(const asiolink::IOAddress& address);
+
+ /// @brief Resets the current pool.
+ void resetPool() {
+ pool_.reset();
+ }
+
+ /// @brief Fetches the current pool.
+ ///
+ /// @return Pointer to the current pool, may be an empty
+ /// pointer.
+ 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.
+typedef boost::shared_ptr<DdnsParams> DdnsParamsPtr;
+
+} // namespace dhcp
+} // namespace isc
+
+#endif // DDNS_PARAMS_H
<< " must not be greater than 128");
}
}
-
+
} // end of namespace isc::dhcp
} // end of namespace isc
// Set evaluate-additional-classes
if (!additional_classes_.empty()) {
- map->set("evaluate-additional-classes",
+ map->set("evaluate-additional-classes",
additional_classes_.toElement());
}
ddns_replace_client_name_mode_(), ddns_generated_prefix_(), ddns_qualifying_suffix_(),
hostname_char_set_(), hostname_char_replacement_(), store_extended_info_(),
cache_threshold_(), cache_max_age_(), ddns_update_on_renew_(),
- ddns_conflict_resolution_mode_(), ddns_ttl_percent_(),
+ ddns_conflict_resolution_mode_(), ddns_ttl_percent_(),
ddns_ttl_(), ddns_ttl_min_(), ddns_ttl_max_(),
allocator_type_(), default_allocator_type_() {
}
/// - ddns-update-on-renew
/// - ddns-ttl-percent
/// - ddns-conflict-resolution-mode
+ /// - ddns-ttl
+ /// - ddns-ttl-min
+ /// - ddns-ttl-max
///
/// Owner types are expected to have public setters for each of these
- /// paramters.
+ /// parameters.
///
- /// @tparam DdnsOwnerPtr pointer to the class type that owns the DDNS parameters
- /// @param config configuration element holding the DDNS paramters to parse.
+ /// @tparam DdnsOwnerPtr pointer to the class type that owns the DDNS parameters.
+ /// @param config configuration element holding the DDNS parameters to parse.
/// @param owner Pointer to the DDNS parameter owner object into which parsed values
/// should be stored.
/// @throw BadValue for various invalid values.
uint32_t ddns_ttl_max = getInteger(config, "ddns-ttl-max");
if (ddns_ttl_max < ddns_ttl_min) {
- isc_throw(BadValue, "ddns-ttl-max: " << ddns_ttl_max
+ isc_throw(BadValue, "ddns-ttl-max: " << ddns_ttl_max
<< " must be greater than ddns-ttl-min: " << ddns_ttl_min);
}
// depend_on_known is now allowed
}
- if (additional &&
+ if (additional &&
(!valid_lft.unspecified() ||
!preferred_lft.unspecified() ||
!offer_lft.unspecified())) {
cfg_option_(new CfgOption()) {
}
-bool
+bool
Pool::inRange(const isc::asiolink::IOAddress& addr) const {
return (first_ <= addr && addr <= last_);
}
-bool
+bool
Pool::clientSupported(const ClientClasses& classes) const {
return (client_classes_.empty() || client_classes_.intersects(classes));
}
-void
+void
Pool::allowClientClass(const ClientClass& class_name) {
if (!client_classes_.contains(class_name)) {
client_classes_.insert(class_name);
}
bool
-Pool::hasDdnsParameters() {
+Pool::hasDdnsParameters() const {
return (!(ddns_send_updates_.unspecified() &&
ddns_override_no_update_.unspecified() &&
ddns_override_client_update_.unspecified() &&
map->set("pool-id", Element::create(static_cast<long long>(id_)));
}
- // Add in DDNS paramters for non-prefix pools.
+ // Add in DDNS parameters for non-prefix pools.
if (type_ != Lease::TYPE_PD) {
if (!ddns_send_updates_.unspecified()) {
map->set("ddns-send-updates", Element::create(ddns_send_updates_));
/// @brief Checks if any of the DDNS parameters has a value.
///
/// @return True if any of the DDNS parameters are specified.
- bool hasDdnsParameters();
+ bool hasDdnsParameters() const;
protected:
}
}
-bool
-DdnsParams::getUpdateOnRenew() const {
- if (!subnet_) {
- 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());
-}
-
-util::Optional<uint32_t>
-DdnsParams::getTtl() const {
- if (!subnet_) {
- return (util::Optional<uint32_t>());
- }
-
- if (pool_) {
- auto optional = pool_->getDdnsTtl();
- if (!optional.unspecified()) {
- return (optional.get());
- }
- }
-
- return (subnet_->getDdnsTtl());
-}
-
-util::Optional<uint32_t>
-DdnsParams::getTtlMin() const {
- if (!subnet_) {
- return (util::Optional<uint32_t>());
- }
-
- if (pool_) {
- auto optional = pool_->getDdnsTtlMin();
- if (!optional.unspecified()) {
- return (optional.get());
- }
- }
-
- return (subnet_->getDdnsTtlMin());
-}
-
-util::Optional<uint32_t>
-DdnsParams::getTtlMax() const {
- if (!subnet_) {
- return (util::Optional<uint32_t>());
- }
-
- if (pool_) {
- auto optional = pool_->getDdnsTtlMax();
- if (!optional.unspecified()) {
- return (optional.get());
- }
- }
-
- return (subnet_->getDdnsTtlMax());
-}
-
-PoolPtr
-DdnsParams::setPoolFromAddress(const asiolink::IOAddress& address) {
- if (!subnet_) {
- /// @todo Not sure this can happen.
- isc_throw(InvalidOperation,
- "DdnsParams::setPoolFromAddress called without a subnet");
- }
-
- pool_ = subnet_->getPool((address.isV4() ? Lease::TYPE_V4 : Lease::TYPE_NA),
- address, false);
- return (pool_);
-}
-
-
} // namespace dhcp
} // namespace isc
#include <dhcpsrv/cfg_consistency.h>
#include <dhcpsrv/client_class_def.h>
#include <dhcpsrv/d2_client_cfg.h>
+#include <dhcpsrv/ddns_params.h>
#include <process/config_base.h>
#include <hooks/hooks_config.h>
#include <cc/data.h>
class CfgMgr;
-/// @brief Convenience container for conveying DDNS behavioral parameters
-/// It is intended to be created per Packet exchange using the selected
-/// subnet passed into functions that require them
-class DdnsParams {
-public:
- /// @brief Default constructor
- DdnsParams() : subnet_(), d2_client_enabled_(false) {}
-
- /// @brief Constructor
- ///
- /// @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 ConstSubnetPtr& subnet, bool d2_client_enabled)
- : subnet_(subnet),
- d2_client_enabled_(d2_client_enabled) {}
-
- /// @brief Returns whether or not DHCP DDNS updating is enabled.
- /// The value is the logical AND of d2_client_enabled_ and
- /// the value returned by subnet_'s getDdnsSendUpdates().
- ///
- /// @return True if updates are enabled, false otherwise or if
- /// subnet_ is empty.
- bool getEnableUpdates() const;
-
- /// @brief Returns whether or not Kea should perform updates, even if
- /// client requested no updates.
- ///
- /// @return The value from the subnet_ or false if subnet_ is empty.
- bool getOverrideNoUpdate() const;
-
- /// @brief Returns whether or not Kea should perform updates, even if
- /// client requested delegation.
- ///
- /// @return The value from the subnet_ or false if subnet_ is empty.
- bool getOverrideClientUpdate() const;
-
- /// @brief Returns how Kea should handle the domain-name supplied by
- /// the client.
- ///
- /// @return The value from the subnet_ or RCM_NEVER if subnet_ is empty.
- D2ClientConfig::ReplaceClientNameMode getReplaceClientNameMode() const;
-
- /// @brief Returns the Prefix Kea should use when generating domain-names.
- ///
- /// @return The value from the subnet_ or an empty string if subnet_ is empty.
- std::string getGeneratedPrefix() const;
-
- /// @brief Returns the suffix Kea should use when to qualify partial
- /// domain-names.
- ///
- /// @return The value from the subnet_ or an empty string if subnet_ is empty.
- std::string getQualifyingSuffix() const;
-
- /// @brief Returns the regular expression describing invalid characters
- /// for client hostnames. If empty, host name scrubbing should not be done.
- ///
- /// @return The value from the subnet_ or an empty string if subnet_ is empty.
- std::string getHostnameCharSet() const;
-
- /// @brief Returns the string to replace invalid characters when scrubbing
- /// hostnames. Meaningful only if hostname_char_set_ is not empty.
- ///
- /// @return The value from the subnet_ or an empty string if subnet_ is empty.
- std::string getHostnameCharReplacement() const;
-
- /// @brief Returns a regular expression string sanitizer
- ///
- /// If the value returned by getHostnameCharSet() is not empty, then it is
- /// used in conjunction the value returned by getHostnameCharReplacment()
- /// (which may be empty) to create and return a StringSanitizer instance.
- /// Otherwise it will return an empty pointer.
- ///
- /// @return pointer to the StringSanitizer instance or an empty pointer
- /// @throw BadValue if the compilation fails.
- isc::util::str::StringSanitizerPtr getHostnameSanitizer() const;
-
- /// @brief Returns whether or not DNS should be updated when leases renew.
- ///
- /// If this is true, DNS should always be updated when leases are
- /// extended (i.e. renewed/rebound) even if the DNS information
- /// has not changed.
- ///
- /// @return True if updates should always be performed.
- bool getUpdateOnRenew() const;
-
- /// @brief Returns percent of lease lifetime to use for TTL
- ///
- /// This value, if greater than zero, is used to calculate the lease lifetime
- /// passed to D2 in the NCR. Otherwise the value is calculated per RFC 4702.
- ///
- /// @return TTL percent as an Optional.
- util::Optional<double> getTtlPercent() const;
-
- /// @brief Returns explicit TTL to use
- ///
- /// This value, if greater than zero, is used as the lifetime
- /// passed to D2 in the NCR.
- ///
- /// @return TTL as an Optional.
- util::Optional<uint32_t> getTtl() const;
-
- /// @brief Returns the minimum TTL to use
- ///
- /// This value, if greater than zero, is used as the lower boundary
- /// for calculated TTLs.
- ///
- /// @return TTL minimum as an Optional.
- util::Optional<uint32_t> getTtlMin() const;
-
- /// @brief Returns the maximum TTL to use
- ///
- /// This value, if greater than zero, is used as the upper boundary
- /// for calculated TTLs.
- ///
- /// @return TTL maximum as an Optional.
- util::Optional<uint32_t> getTtlMax() const;
-
- /// @brief Returns the DDNS config resolution mode for kea-dhcp-ddns
- ///
- /// This value is communicated to D2 via the NCR.
- ///
- /// @return the DDNS conflict resolution mode
- std::string getConflictResolutionMode() const;
-
- /// @brief Returns the subnet-id of the subnet associated with these parameters
- ///
- /// @return value of subnet-id (or 0 if no subnet is associated)
- SubnetID getSubnetId() const {
- if (subnet_) {
- return (subnet_->getID());
- } else {
- return (0);
- }
- }
-
- 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.
-typedef boost::shared_ptr<DdnsParams> DdnsParamsPtr;
-
/// @brief Specifies current DHCP configuration
///
/// @todo Migrate all other configuration parameters from cfgmgr.h here
///
/// If ddns-ttl is specified none of the others can be.
/// If ddns-ttl-min and ddns-ttl-max are specified max cannot
- /// be less than min.
+ /// be less than min.
///
/// @throw Throws BadValue if any of the rules are violated.
void sanityChecksDdnsTtlParameters() const;
/// @file
/// @brief Callout Library
///
-/// This is the source of a test library for the basic DHCP parser
+/// This is the source of a test library for the basic DHCP parser
/// tests. It just has to load - nothing else.
#include <config.h>
}
// Veriy we have the expected count of log messages.
- ASSERT_EQ(countFile("DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES"),
+ ASSERT_EQ(countFile("DHCPSRV_CLASS_WITH_ADDITIONAL_AND_LIFETIMES"),
exp_log_count);
}
}
///
/// As this uses the
/// same parser as Network derivatives we skip retesting all the
- /// invalid permuations. This test ensures all supported
+ /// invalid permutations. This test ensures all supported
/// parameters can be set.
/// @tparam PoolListParserType type of pool list parser to use, Pools4ListParser
/// or Pools6ListParser.
/// @param pool1 string pool specification for the first pool
/// @param pool2 string pool specification for the first pool
template<typename PoolListParserType>
- void validPoolDdnsParmaters(const std::string& pool1, const std::string& pool2) {
+ void validPoolDdnsParameters(const std::string& pool1, const std::string& pool2) {
std::stringstream ss;
ss <<
// Verifies valid DDNS parameters in v4 pools.
TEST_F(DhcpParserTest, validDdnsParmatersPool4) {
- validPoolDdnsParmaters<Pools4ListParser>("192.0.1.0/24", "192.0.2.0/24");
+ validPoolDdnsParameters<Pools4ListParser>("192.0.1.0/24", "192.0.2.0/24");
}
// Verifies valid DDNS parameters in v6 pools.
TEST_F(DhcpParserTest, validDdnsParmatersPool6) {
- validPoolDdnsParmaters<Pools6ListParser>("2001:db8:1::/64", "2001:db8:2::/64");
+ validPoolDdnsParameters<Pools6ListParser>("2001:db8:1::/64", "2001:db8:2::/64");
}
} // Anonymous namespace
SCOPED_TRACE(oss.str());
testNCR(CHG_ADD, true, true, "MYHOST.example.com.",
"000001E356D43E5F0A496D65BCA24D982D646140813E3"
- "B03AB370BFF46BFA309AE7BFD", CHECK_WITH_DHCID,
+ "B03AB370BFF46BFA309AE7BFD", CHECK_WITH_DHCID,
scenario.ddns_ttl_percent_,
scenario.ddns_ttl_,
scenario.ddns_ttl_min_,
__LINE__,
R"^({
"name": "one",
- "ddns-ttl-percent": 5.0
+ "ddns-ttl-percent": 5.0
})^",
5.0, 0, 0, 0
},{
__LINE__,
R"^({
"name": "one",
- "ddns-ttl-min": 25
+ "ddns-ttl-min": 25
})^",
0.0, 0, 25, 0
},{
__LINE__,
R"^({
"name": "one",
- "ddns-ttl-max": 150
+ "ddns-ttl-max": 150
})^",
- 0.0, 0, 0, 150
+ 0.0, 0, 0, 150
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-min": 25,
- "ddns-ttl-max": 150
+ "ddns-ttl-max": 150
})^",
- 0.0, 0, 25, 150
+ 0.0, 0, 25, 150
},{
__LINE__,
R"^({
"name": "one",
"ddns-ttl-percent": 5.0,
"ddns-ttl-min": 25,
- "ddns-ttl-max": 150
+ "ddns-ttl-max": 150
})^",
- 5.0, 0, 25, 150
+ 5.0, 0, 25, 150
}};
for (const auto& scenario : scenarios) {
- std::stringstream oss;
+ std::stringstream oss;
oss << "scenario at " << scenario.line_no_;
SCOPED_TRACE(oss.str());
ASSERT_NO_THROW_LOG(network = parser.parse(config_element));
ASSERT_TRUE(network);
- EXPECT_EQ(network->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
- EXPECT_EQ(network->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
+ EXPECT_EQ(network->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
+ EXPECT_EQ(network->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
+
+ EXPECT_EQ(network->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
+ EXPECT_EQ(network->getDdnsTtl(), scenario.ddns_ttl_);
- EXPECT_EQ(network->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
- EXPECT_EQ(network->getDdnsTtl(), scenario.ddns_ttl_);
-
- EXPECT_EQ(network->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
- EXPECT_EQ(network->getDdnsTtlMin(), scenario.ddns_ttl_min_);
+ EXPECT_EQ(network->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
+ EXPECT_EQ(network->getDdnsTtlMin(), scenario.ddns_ttl_min_);
- EXPECT_EQ(network->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
- EXPECT_EQ(network->getDdnsTtlMax(), scenario.ddns_ttl_max_);
+ EXPECT_EQ(network->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
+ EXPECT_EQ(network->getDdnsTtlMax(), scenario.ddns_ttl_max_);
}
}
R"^({
"name": "one",
"ddns-ttl": 100,
- "ddns-ttl-max": 150
+ "ddns-ttl-max": 150
})^",
"cannot specify both ddns-ttl-max and ddns-ttl (<string>:1:2)"
},{
R"^({
"name": "one",
"ddns-ttl-min": 150,
- "ddns-ttl-max": 25
+ "ddns-ttl-max": 25
})^",
"ddns-ttl-max: 25 must be greater than ddns-ttl-min: 150 (<string>:1:2)"
}};
for (const auto& scenario : scenarios) {
- std::stringstream oss;
+ std::stringstream oss;
oss << "scenario at " << scenario.line_no_;
SCOPED_TRACE(oss.str());
/// from the proper source.
///
/// @param subnet Subnet under test.
- /// @param address Address to locate the pool within the subnet via
+ /// @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) {
} else {
EXPECT_EQ(params->getOverrideNoUpdate(), subnet->getDdnsOverrideNoUpdate().get());
}
-
+
if (pool && !(pool->getDdnsOverrideClientUpdate().unspecified())) {
EXPECT_EQ(params->getOverrideClientUpdate(), pool->getDdnsOverrideClientUpdate().get());
} else {
subnet->setHostnameCharReplacement("X");
subnet->setHostnameCharSet("[^A-Z]");
- // Create a pool and add it to the subnet.
+ // 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));
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::"),
+ // 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));
subnet->addPool(pdpool2);
// Add several options to the subnet.
- subnet->getCfgOption()->add(*test_options_[0], test_options_[0]->space_name_);
- subnet->getCfgOption()->add(*test_options_[1], test_options_[1]->space_name_);
- subnet->getCfgOption()->add(*test_options_[2], test_options_[2]->space_name_);
+ subnet->getCfgOption()->add(*test_options_[0], test_options_[0]->space_name_);
+ subnet->getCfgOption()->add(*test_options_[1], test_options_[1]->space_name_);
+ subnet->getCfgOption()->add(*test_options_[2], test_options_[2]->space_name_);
test_subnets_.push_back(subnet);